乐观锁:每次不加锁而是假设没有冲突而去完成某项操作,如果失败就重试,直到成功为止
悲观锁:synchronized是独占锁即悲观锁,会导致其他所有需要锁的线程挂起,等待有锁的线程释放锁
乐观锁实现方式:
-
取出记录时,获取当前version
-
更新时,带上这个version
-
执行更新时,set version = newVersion where version = oldVersion
-
如果version不对,就更新失败
#乐观锁:先查询,获得版本号 -- A update user set name = "wsk",version = version+1 where id = 1 and version = 1 -- B (B线程抢先完成,此时version=2,会导致A线程修改失败!) update user set name = "wsk",version = version+1 where id = 1 and version = 1
测试一下Mybatis-Plus乐观锁插件
1、给数据库中增加version字段
2、实体类加对应的字段
@Version//乐观锁version注解
private Integer version;
3、注册组件
//扫描mapper文件夹
@MapperScan("com.huang.mapper")//交给mybatis做的,可以让这个配置类做扫描,将主类注解删除
@EnableTransactionManagement//自动管理事务
@Configuration//配置类
public class MyBatisPlusConfig {
//注册乐观锁插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor(){
return new OptimisticLockerInterceptor();
}
}
4、测试
- 成功
//测试乐观锁成功
public void testOpimisticLocker(){
//1、查询用户信息
User user = userMapper.selectById(1L);
//2、修改用户信息
user.setAge(18);
user.setEmail("1024955508@qq.com");
//3、执行更新操作
userMapper.updateById(user);
}
-
模拟多线程失败场景
//测试乐观锁失败 @Test//测试乐观锁失败 多线程下 public void testOptimisticLocker2(){ //线程1 User user1 = userMapper.selectById(1L); user1.setName("乐观成功"); //模拟另外一个线程执行了插队操作 User user2 = userMapper.selectById(1L); user2.setName("插队"); userMapper.updateById(user2); //自旋锁来多次尝试提交! userMapper.updateById(user1);//如果没有乐观锁就会覆盖插队线程的值 }