前言
在面试过程中,我们经常会被问道乐观锁,悲观锁!这个其实非常简单!
一、解释
- 乐观锁 : 故名思意十分乐观,它总是认为不会出现问题,无论干什么不去上锁!如果出现了问题,再次更新值测试。
- 悲观锁: 故名思意十分悲观,它总是认为总是出现问题,无论干什么都会上锁!再去操作!
我们这里主要讲解 乐观锁机制!
乐观锁实现方式:
- 取出记录时,获取当前 version
- 更新时,带上这个version.
- 执行更新时,
set version = newVersion where version = oldVersion
- 如果version不对,就更新失败
乐观锁:1、先查询,获得版本号 version = 1
– A
update user set name = "kuangshen", version = version + 1
where id = 2 and version = 1
– B 线程抢先完成,这个时候 version = 2
,会导致 A 修改失败。
update user set name = "kuangshen", version = version + 1
where id = 2 and version = 1
二、测试MP的乐观锁插件
1.给数据库中增加version字段!
2.我们实体类加对应的字段
在对应的entity
实体类中编写字段、
@Version //乐观锁Version注解
private Integer version;
3.注册组件
需要在config
包下 的配置类中编写代码,注册乐观锁插件。
// 扫描我们的 mapper 文件夹
@MapperScan("com.kuang.mapper")
@EnableTransactionManagement
@Configuration // 配置类
public class MyBatisPlusConfig {
// 注册乐观锁插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}
4.测试一下!
在测试类@Test
中编写测试代码:
// 测试乐观锁成功!
@Test
public void testOptimisticLocker(){
// 1、查询用户信息
User user = userMapper.selectById(1L);
// 2、修改用户信息
user.setName("kuangshen");
user.setEmail("24736743@qq.com");
// 3、执行更新操作
userMapper.updateById(user);
}
测试乐观锁失败!多线程下,表示线程1在执行操作的时候,突然被另外一个线程插队抢先执行了操作,并提交了的修改,这个时候线程1再提交的数据就无效。那么程序对于线程1来说,线程1提交的数据则不会成功。这个时候我们可以用自旋锁来多次尝试提交。
如果没有乐观锁就会覆盖插队线程的值! 就应该是改变的是由线程1指定修改的值。
@Test
public void testOptimisticLocker2(){
// 线程 1
User user = userMapper.selectById(1L);
user.setName("kuangshen111");
user.setEmail("24736743@qq.com");
// 模拟另外一个线程执行了插队操作
User user2 = userMapper.selectById(1L);
user2.setName("kuangshen222");
user2.setEmail("24736743@qq.com");
userMapper.updateById(user2);
// 自旋锁来多次尝试提交!
userMapper.updateById(user); // 如果没有乐观锁就会覆盖插队线程的值!
}
发现了名字修改成了“kuangshen222” 修改成线程2的值了。