本章导学:
- 什么是乐观锁
- 为什么要使用乐观锁
- 基于SpringBoot实现乐观锁
一、什么是乐观锁
当要更新一条记录的时候,希望这条记录没有被别人更新
乐观锁实现方式:
- 取出记录时,获取当前 version
- 更新时,带上这个 version
- 执行更新时, set version = newVersion where version = oldVersion
- 如果 version 不对,就更新失败
二、为什么要使用乐观锁
我们先看一个场景:
某公司产品销量不好,于是老板吩咐小王把产品定价下调50元,小王一口答应了下来,但是小王还在摸鱼,没有马上去修改产品的定价。过了一会老板觉得下调50元太亏了,于是吩咐另外一个员工小白去把产品定价下调30元。不巧的是,小王和小白先后对这条数据进行了更新,于是产品价格被调低了80元,老板亏死了~。
我们用代码模拟一下这个场景
我们观察一下sql语句
那如果去解决这个并发冲突呢?我们可以采取以下的方法(乐观锁)
- 取出记录时,获取当前 version
- 更新时,带上这个 version
- 执行更新时, set version = newVersion where version = oldVersion
- 如果 version 不对,就更新失败
三、基于SpringBoot实现乐观锁
我们新建一个配置类,添加乐观锁拦截器
package com.brrbaii.Config;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MpConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
//1,定义Mp拦截器
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
//2,添加具体的拦截器,这里添加的为分页拦截器
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
//3,添加乐观锁拦截器
mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return mybatisPlusInterceptor;
}
}
在数据库和实体类上各自添加一个Version字段
重新执行测试方法
@Test
public void test02(){
//需求:原价7800,最终降价为7770
//小王进行数据
Dish dishAA = dishMapper.selectById(1397849739276890114l);
//小白进行查询
Dish dishBB = dishMapper.selectById(1397849739276890114l);
//小王修改价格,下调50元
dishAA.setPrice(dishAA.getPrice().subtract(new BigDecimal(50)));
dishMapper.updateById(dishAA);
//小白修改价格,下调30元
dishBB.setPrice(dishAA.getPrice().subtract(new BigDecimal(30)));
dishMapper.updateById(dishBB);
}
小王执行的修改语句 :
小王此时进行修改会先判断version是否等于从数据里查出来的version,然后对version自增1
小白执行的修改语句:
由于小王操作后,version已经从0加到1了,所以小白的where version = 0判断为false,更新失败
乐观锁实现方法总结:
在MybatisPlusInterceptor添加乐观锁拦截器(OptimisticLockerInnerInterceptor)- 在实体类和数据库上分别添加version字段