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

乐观锁

乐观锁是一种并发控制机制,用于确保在更新记录时,该记录未被其他事务修改。MongoPlus 提供了 OptimisticLockerInterceptor 插件,使得在应用中实现乐观锁变得简单。

乐观锁的实现原理

乐观锁的实现通常包括以下步骤:

  1. 读取记录时,获取当前的版本号(version)。
  2. 在更新记录时,将这个版本号一同传递。
  3. 执行更新操作时,设置 version = newVersion 的条件为 version = oldVersion
  4. 如果版本号不匹配,则更新失败。

配置乐观锁插件

要使用乐观锁插件,需要进行两步配置:

1. 配置插件

java
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor(){
    OptimisticLockerInterceptor optimisticLockerInterceptor = new OptimisticLockerInterceptor();
    // 修改失败后是否抛出异常抛出异常
    optimisticLockerInterceptor.setUpdateFailException(new RuntimeException("修改失败"));
    // 未获取到乐观锁字段是否抛出异常
    optimisticLockerInterceptor.setVersionIsNullException(new MongoPlusException("未获取到乐观锁字段"));
    // 设置乐观锁自增值
    optimisticLockerInterceptor.setAutoInc(1);
    // 是否开启重试
    optimisticLockerInterceptor.enableRetry(getRetryStrategy());
    return optimisticLockerInterceptor;
}

/**
 * 获取重试策略
 */
Retry getRetryStrategy() {
    return Retry.builder()
            // 最大重试次数
            .maxRetryNum(10)
            // 首次命中回调
            .hitRetry(updateRetryResult -> System.out.println("首次命中: " + updateRetryResult))
            // 修改成功回调
            .onSuccess(object -> System.out.println("修改成功: " + object))
            // 修改失败回调
            .onFailure(object -> System.out.println("修改失败: " + object))
            // 达到最大重试次数失败后的备用逻辑
            .fallback(((updateRetryResult, invocation) -> {
                try {
                    return invocation.proceed();
                } catch (Throwable e) {
                    throw new RuntimeException(e);
                }
            }))
            // 每次重试增加version值
            .autoVersionNum(1)
            // 重试是否继续执行后续拦截器,默认为true
            // 如果后续的执行器中,进行了某些操作,请将该属性设置为false。比如在后续拦截器中做了修改其他表的操作,在重试时则会修改多次
            .processIntercept(true)
            // 重试间隔时间
            .retryInterval(100L)
            // 开启异步重试
            // 启异步后,会立即返回当前更新失败的响应,并且异步的重试,不受事务控制。可以通过回调配置查看最终结果
            .asyncRetry(true)
            .build();
}

2. 在实体类字段上添加 @Version 注解

在实体类中,需要在表示版本号的字段上添加 @Version 注解:

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

public class YourEntity {
    @Version
    private Integer version;
    // 其他字段...
}

注意事项

  • 仅支持int类型。

  • 支持内置的 updateById(entity)update(entity, wrapper), saveOrUpdate(entity), 方法,也可通过条件构造器手动设置updateWrapper.set("version",0)

  • update(entity, wrapper) 方法中,wrapper 不能复用。

通过以上配置和实体类中的 @Version 注解,你就可以在 MongoPlus 应用中轻松实现乐观锁,有效防止并发更新时的数据冲突。