文章目录
- 前言
- 0. OptimisticLockerInnerInterceptor 介绍
- 1. Mybatis-plus 实现乐观锁的原理
- 2. 自定义乐观锁插件
- 1. 创建自定义乐观锁插件
- 2. 配置自定义乐观锁插件
- 3. 总结
- 👏作者简介:大家好,我是冰点,从业11年,目前在物流独角兽企业从事技术方面工作,
- 🍂博主正在努力完成2023计划中:以梦为马,扬帆起航,2023追梦人
- 📝联系方式:iceicepip,加我进群,大家一起学习,一起进步👀
前言
有的时候我们需要对mybatis-plus的乐观锁插件进行自定义修改。那么其实mybatis 是已经有个默认的实现,我们只需要将其继承并扩展即可。
0. OptimisticLockerInnerInterceptor 介绍
当要更新一条记录的时候,希望这条记录没有被别人更新
乐观锁实现方式:
- 取出记录时,获取当前 version
- 更新时,带上这个 version
- 执行更新时, set version = newVersion where version = oldVersion
- 如果 version 不对,就更新失败 但是我们也可以根据自己的业务需求实现自定义的乐观锁插件。
Mybatis-Plus虽然已经提供了一个默认的乐观锁插件,但是我们也可以根据自己的业务需求实现自定义的乐观锁插件。
1. Mybatis-plus 实现乐观锁的原理
在MyBatis-Plus中,我们可以通过在实体类的版本号字段上添加@Version注解来标识乐观锁字段。在更新一条记录时,MyBatis-Plus会自动将版本号字段的值加1,然后将新的版本号值与更新语句一起发送到数据库中。如果更新成功,说明版本号没有冲突,否则会抛出乐观锁异常。
1. 在Mapper接口中定义更新方法
int updateById(@Param(Constants.ENTITY) T entity);
2. 在实体类的版本号字段上添加@Version注解
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String name;
private Integer age;
@Version
private Integer version;
// ...
}
-
在执行更新操作时,MyBatis-Plus会拦截更新语句,并根据实体类中的@Version注解来判断是否需要加入乐观锁机制。如果实体类中没有@Version注解,则不使用乐观锁机制。
-
如果实体类中有@Version注解,则MyBatis-Plus会自动将版本号字段的值加1,并将新的版本号值与更新语句一起发送到数据库中。
-
在数据库中执行更新操作时,MyBatis-Plus会根据更新语句中的版本号值来判断是否需要进行乐观锁校验。如果版本号值与数据库中的版本号值不一致,则说明版本号冲突,此时会抛出乐观锁异常。
2. 自定义乐观锁插件
1. 创建自定义乐观锁插件
先创建一个继承自Mybatis-Plus的OptimisticLockerInnerInterceptor的自定义乐观锁插件类,然后重写其beforeUpdate()方法来实现自己的乐观锁逻辑。
CustomOptimisticLockerInterceptor
public class CustomOptimisticLockerInterceptor extends OptimisticLockerInnerInterceptor {
@Override
public void beforeUpdate(Executor executor, MappedStatement ms, Object parameter) {
// 获取实体类对象
Object entity = getEntityFromParameter(parameter);
// 获取乐观锁注解
Version versionAnnotation = entity.getClass().getAnnotation(Version.class);
if (versionAnnotation != null) {
// 获取版本号字段名
String versionColumn = versionAnnotation.value();
// 获取版本号字段的值
Object versionValue = getFieldValue(entity, versionColumn);
// 如果版本号为空或者为0,则抛出乐观锁异常
if (版本号为空或为0) {
throw new OptimisticLockException("乐观锁异常:版本号为空或为0");
}
// 更新版本号字段值
setFieldValue(entity, versionColumn, Integer.parseInt(versionValue.toString()) + 1);
}
// 调用父类的beforeUpdate()方法
super.beforeUpdate(executor, ms, parameter);
}
private Object getEntityFromParameter(Object parameter) {
if (parameter instanceof Map) {
Map map = (Map) parameter;
if (map.containsKey("et")) {
return map.get("et");
}
} else if (parameter != null) {
return parameter;
}
throw new MybatisPlusException("Failed to process, the parameter object is null.");
}
private Object getFieldValue(Object entity, String fieldName) {
try {
Field field = entity.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(entity);
} catch (Exception e) {
throw new MybatisPlusException("Failed to get field value.", e);
}
}
private void setFieldValue(Object entity, String fieldName, Object value) {
try {
Field field = entity.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(entity, value);
} catch (Exception e) {
throw new MybatisPlusException("Failed to set字段值.", e);
}
}
}
2. 配置自定义乐观锁插件
在Mybatis-Plus的配置文件中,我们可以将自定义乐观锁插件配置为GlobalConfiguration的属性之一。下面是一个示例:
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new CustomOptimisticLockerInterceptor());
return interceptor;
}
}
在这个示例中,我们将自定义乐观锁插件添加到MybatisPlusInterceptor中,然后将其作为bean配置在MybatisPlusConfig类中。这样,我们就成功地配置了自定义乐观锁插件。
3. 总结
通过自定义乐观锁插件,我们可以根据自己的业务需求灵活地实现乐观锁机制。在实现自定义乐观锁插件时,我们需要重写OptimisticLockerInnerInterceptor的beforeUpdate()方法,并实现自己的乐观锁逻辑。最后,我们需要将自定义乐观锁插件配置到Mybatis-Plus的配置文件中。
在重写beforeUpdate()方法时,我们需要获取实体类对象、乐观锁注解、版本号字段名和版本号字段的值,并根据业务需求更新版本号字段的值。如果版本号为空或者为0,我们需要抛出乐观锁异常。
最后,我们需要将自定义乐观锁插件添加到MybatisPlusInterceptor中,这样它才能生效。