Skip to content
广告❤️成为赞助商

Optimistic Lock ​

Optimistic lock is a concurrency control mechanism used to ensure that when a record is updated, it has not been modified by other transactions. MongoPlus provides the OptimisticLockerInterceptor plugin, making it simple to implement optimistic locking in your application.

How Optimistic Lock Works ​

The implementation of optimistic lock generally includes the following steps:

  1. When reading a record, get the current version number (version).
  2. When updating the record, pass this version number along.
  3. During the update operation, set the condition version = newVersion as version = oldVersion.
  4. If the version number does not match, the update fails.

Configuring the Optimistic Lock Plugin ​

To use the optimistic lock plugin, two steps are required:

1. Configure the Plugin ​

java
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor(){
    OptimisticLockerInterceptor optimisticLockerInterceptor = new OptimisticLockerInterceptor();
    // Whether to throw an exception when the update fails
    optimisticLockerInterceptor.setUpdateFailException(new RuntimeException("Update failed"));
    // Whether to throw an exception when the version field is not obtained
    optimisticLockerInterceptor.setVersionIsNullException(new MongoPlusException("Version field not obtained"));
    // Set the increment value for the optimistic lock
    optimisticLockerInterceptor.setAutoInc(1);
    // Enable retry
    optimisticLockerInterceptor.enableRetry(getRetryStrategy());
    return optimisticLockerInterceptor;
}

/**
 * Get retry strategy
 */
Retry getRetryStrategy() {
    return Retry.builder()
            // Maximum retry count
            .maxRetryNum(10)
            // Callback on first hit
            .hitRetry(updateRetryResult -> System.out.println("First hit: " + updateRetryResult))
            // Callback on successful update
            .onSuccess(object -> System.out.println("Update successful: " + object))
            // Callback on failed update
            .onFailure(object -> System.out.println("Update failed: " + object))
            // Fallback logic after reaching maximum retries
            .fallback(((updateRetryResult, invocation) -> {
                try {
                    return invocation.proceed();
                } catch (Throwable e) {
                    throw new RuntimeException(e);
                }
            }))
            // Increase version number on each retry
            .autoVersionNum(1)
            // Whether to continue executing subsequent interceptors during retry (default true)
            // If subsequent interceptors perform other operations, set this to false.
            // For example, if subsequent interceptors modify other tables, retry will modify them multiple times.
            .processIntercept(true)
            // Retry interval
            .retryInterval(100L)
            // Enable asynchronous retry
            // When async retry is enabled, the current update failure response is returned immediately,
            // and the asynchronous retry is not under transaction control. You can use callbacks to monitor the final result.
            .asyncRetry(true)
            .build();
}

2. Add @Version Annotation on Entity Field ​

In your entity class, add the @Version annotation on the field representing the version number:

java
import com.mongoplus.annotation.collection.Version;

public class YourEntity {
    @Version
    private Integer version;
    // Other fields...
}

Notes ​

  • Only int type is supported.
  • Supported methods include built-in updateById(entity), update(entity, wrapper), saveOrUpdate(entity). You can also manually set updateWrapper.set("version",0) via a condition builder.
  • In update(entity, wrapper) method, the wrapper cannot be reused.

With the above configuration and the @Version annotation on your entity class, you can easily implement optimistic locking in MongoPlus, effectively preventing data conflicts during concurrent updates.