目录
乐观锁与悲观锁
乐观锁:每次获取数据的时候,都不会担心数据被修改,所以每次获取数据的时候都不会 进行加锁,但是在更新数据的时候需要判断该数据是否被别人修改过。如果数据被其他线程修改,则不进行数据更新,否则,更新数据。由于数据没有进行加锁,期间该数据可以被其他线程进行读写操作。
悲观锁:它总是认为肯定会出现问题,无论干什么都会上锁,再去操作!
乐观锁的实现方式
- 取出记录时,获取当前的version
- 更新时,带上version
- 执行更新时,set version = new Version where version = oldVersion
- 如果version不对,就会更新失败
测试乐观锁插件
我们在表中新建一个version字段,并让默认值设置为1
保存后效果如下
实体类字段属性上需要增加注解
@Version //乐观锁
private Integer version;
编写配置类来注册乐观锁插件
//扫描我的mapper文件夹
@MapperScan("com.lt.mapper")
@EnableTransactionManagement
//配置类
@Configuration
public class MybatisPlusConfig {
//注册乐观锁插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor(){
return new OptimisticLockerInterceptor();
}
}
测试乐观锁执行成功
//测试乐观锁成功
@Test
public void testOptimisticLocker(){
//1查询用户信息
User user = userMapper.selectById(1L);
//2修改用户信息
user.setName("lt");
user.setEmail("123456@qq.com");
//3执行更新操作
userMapper.updateById(user);
}
单线程下乐观锁执行成功,version+1
测试乐观锁执行失败
//多线程下测试乐观锁失败
@Test
public void testOptimisticLocker2(){
//线程1
User user = userMapper.selectById(1L);
user.setName("我又来啦");
user.setEmail("98989@qq.com");
//模拟另一个线程执行了插队操作
User user2 = userMapper.selectById(1L);
user2.setName("第二个线程来啦");
user2.setEmail("213321@qq.com");
userMapper.updateById(user2);
//自旋锁来多次尝试提交,如果我们没有使用乐观锁就会覆盖插队线程的值
userMapper.updateById(user);
}
version又加一,保留的是插队线程传进去的值