文章目录
- 前言
 - 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中,这样它才能生效。



















