← 返回首页
MybatisPlus基础教程(七)
发表时间:2020-03-30 00:32:24
讲解MybatisPlus的乐观锁

1.乐观锁

主要适用场景:当要更新一条记录的时候,希望这条记录没有被别人更新,也就是说实现线程安全的数据更新。

乐观锁实现方式:

  1. 取出记录时,获取当前version
  2. 更新时,带上这个version
  3. 执行更新时, set version = newVersion where version = oldVersion
  4. 如果version不对,就更新失败

2.乐观锁实现步骤

1)实体类添加version字段

@Data
@Entity
public class Users {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY) //auto_increment类型
    @TableId(type = IdType.AUTO)
    private Long id;
    private String name;
    private Integer age;
    private String email;

    @TableField(fill = FieldFill.INSERT)
    private Date createTime;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;

    @TableLogic
    @TableField(fill = FieldFill.INSERT)
    private Integer deleted;
    //乐观锁字段
    @Version
    @TableField(fill = FieldFill.INSERT)
    private Integer version;
}

2)元对象处理器接口添加version的insert默认值

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    private static final Logger LOGGER = LoggerFactory.getLogger(MyMetaObjectHandler.class);

    @Override
    public void insertFill(MetaObject metaObject) {

        LOGGER.info("start insert fill ....");
        this.setFieldValByName("createTime", new Date(), metaObject);
        this.setFieldValByName("updateTime", new Date(), metaObject);
        this.setFieldValByName("deleted", 0, metaObject);
        //元对象处理器接口添加version的insert默认值
        this.setFieldValByName("version", 1, metaObject);

    }

    @Override
    public void updateFill(MetaObject metaObject) {
        LOGGER.info("start update fill ....");
        this.setFieldValByName("updateTime", new Date(), metaObject);
    }
}

特别说明:

3)在 MpConfig 中注册 Bean 注意:添加@EnableTransactionManagement注解。

@EnableTransactionManagement
@Configuration
@MapperScan("com.simoniu.mpdemo.mapper")
public class MpConfig {
    //逻辑删除插件
    @Bean
    public ISqlInjector sqlInjector() {
        return new LogicSqlInjector();
    }

    // 乐观锁插件
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
        return new OptimisticLockerInterceptor();
    }

}

4)测试

    //测试更新成功
    @Test
    public void testUpdate() {
        Users u = usersMapper.selectById(1L);
        u.setName("张无忌");
        int result = usersMapper.updateById(u);
        System.out.println("受影响的记录条数是:" + result);

    }

测试后分析打印的sql语句,将version的数值进行了加1操作。

    //测试更新失败
    @Test
    public void testUpdate() {
        Users u = usersMapper.selectById(1L);
        u.setName("张无忌");
        //模拟取出数据后,数据库中version实际数据比取出的值大,即已被其它线程修改并更新了version
        u.setVersion(u.getVersion() - 1);
        int result = usersMapper.updateById(u);
        System.out.println("受影响的记录条数是:" + result);

    }

测试后分析打印的sql语句,并不报错,但是更新失败。

在mybatisplus 3.4.0版本之后,实现乐观锁插件的拦截器类发生了变化,具体改变如下:

//基于mybatisplus 3.4.0 的写法
 @Bean
 public MybatisPlusInterceptor optimisticLockerInnerInterceptor() {
     MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
     interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
     return interceptor;
}