[toc]

[toc]

MyBatisPlus实现乐观锁

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

乐观锁实现方式:

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

![9 乐观锁](/medias/mybatisplus/9 乐观锁.png)

1. 数据库中添加version字段

1
ALTER TABLE `user` ADD COLUMN `version` INT

img

2. 实体类添加version字段

1
2
3
4
// 并添加 @Version 注解
@Version
@TableField(fill = FieldFill.INSERT)
private Integer version;

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

image-20201009184836121

1
2
3
4
5
@Override
public void insertFill(MetaObject metaObject) {
......
this.setFieldValByName("version", 1, metaObject);
}

特别说明:

  • 支持的数据类型只有 int,Integer,long,Long,Date,Timestamp,LocalDateTime

  • 整数类型下 newVersion = oldVersion + 1

  • newVersion会回写到 entity 中仅支持 updateById(id)update(entity, wrapper) 方法

  • update(entity, wrapper) 方法下, wrapper 不能复用!!

4. 在 MybatisPlusConfig 中注册 Bean

创建配置类

  1. @EnableTransactionManagement
  2. @Configuration
  3. @MapperScan("com.atguigu.mybatis_plus.mapper"
  4. OptimisticLockerInterceptor类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package cn.justweb.mybatisplus.config;


@EnableTransactionManagement
@Configuration
@MapperScan("cn.justweb.mybatisplus.mapper")
public class MybatisPlusConfig {

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

5. 测试乐观锁可以修改成功

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* 测试 乐观锁插件
*/
@Test
public void testOptimisticLocker() {

//查询
User user = userMapper.selectById(1L);
//修改数据
user.setName("Helen Yao2");
user.setEmail("helen@qq.com");
//执行更新
userMapper.updateById(user);
}

6. 测试乐观锁修改失败

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* 测试 乐观锁失败
*/
@Test
public void testOptimisticLockerFail() {

//查询
User user = userMapper.selectById(1248825496112750594L);

//修改数据
user.setName("Helen Yao222");
user.setEmail("helen22@qq.com");

// 模拟取出数据,数据库中的version实际比取出的值大,即以被其他线程修改并更新了version
user.setVersion(user.getVersion()-1);

//执行更新
userMapper.updateById(user);
}