配置MyBatis Plus 的乐观锁功能
一. 回顾CAS乐观锁
乐观锁有两种实现方式:
- 版本号
- CAS机制;
CAS:
-
CAS
即Compare and Set
,是乐观锁的一种;是非阻塞的轻量级的锁; -
需要保证变量的可见性,所以配合
volatile
使用; -
乐观锁思想即不怕别的线程来修改共享变量;悲观锁即阻塞式索,同一时间只允许一个线程去访问资源;
思想:
- 外面是用
while(true)
死循环不断尝试(自旋) ; - 线程从【主内存】中拷贝共享变量到【工作内存】,即获取旧值;
- 使用
CompareAndSet
尝试修改,判断当前共享变量的值是否等于工作内存中的旧值,是则修改成功,反之失败;
当前共享变量的值和旧值相等,即说明线程从获取旧值到修改这段时间内,其他线程没有修改这个共享变量的值(或者ABA情况);
例:银行转账
用prev代表余额并记录下来,余额即工作内存从主内存获取的变量的旧值;
next是要修改的值;
而是否修改成功,取决于当前余额的值(最新值)是否等于之前记录的prev旧值;
总结:
优点:
1.无所并发,效率高
缺点:
1.只能保证一个共享变量的原子操作;而多个变量使用互斥锁更容易
2.while(true )长时间自旋转导致开销大
二. 配置MyBatis Plus 的乐观锁
(1)数据库:添加version版本号
在数据库表中加一个version版本号字段;
(2)实体类:添加version版本号属性,@Version注解
2.实体类中也加version字段,添加 @Version
表示这是版本号,version会由MyBatisPluas自动递增,通过版本号变更表示线程已经修改过;
(3)定义拦截器
定义拦截器对sql进行动态追加!
和配置分页查询一样,先定义拦截器,再添加具体哪种拦截器;
注意:分页查询功能和乐观锁功能需要使用拦截器;
(4)开始修改
①先要通过id获取一个查询对象,主要是获取 version
旧值;
②使用 updateById
修改,乐观锁会 判断当前version值(最新值)和之前查询得的旧值是否相等,相等即修改成功,否则失败;
结果:
user2修改成功,user修改失败:
解析sql:
user和user2都获取了version旧值为3,当user2修改后version变成4;
此时user再尝试修改时,之前获取的旧值3和当前version=4不等,则修改失败;