乐观锁
乐观锁是一种并发控制机制,用于确保在更新记录时,该记录未被其他事务修改。MongoPlus 提供了
OptimisticLockerInterceptor
插件,使得在应用中实现乐观锁变得简单。
乐观锁的实现原理
乐观锁的实现通常包括以下步骤:
- 读取记录时,获取当前的版本号(version)。
- 在更新记录时,将这个版本号一同传递。
- 执行更新操作时,设置
version = newVersion
的条件为version = oldVersion
。 - 如果版本号不匹配,则更新失败。
配置乐观锁插件
要使用乐观锁插件,需要进行两步配置:
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 应用中轻松实现乐观锁,有效防止并发更新时的数据冲突。