良好的java基础, 熟悉SpringBoot框架,熟悉Mybatis框架
教学目标了解并掌握MyBatis-Plus 乐观锁实现
视频教程MyBatisPlus实战教程与开发建议
概念多线程环境下如何保证数据库 *** 作安全呢?常用的一种解决方案就是对 *** 作数据表进行加锁处理。根据实现思路不同分:悲观锁与乐观锁2种。
悲观锁:悲观的认为多事务 *** 作同一数据是及其不安全的,所以A事务在 *** 作数据时,其他任何事务不允许对该数据进行修改,只能等待A事务 *** 作结束后才可以执行。
乐观锁:乐观的认为A事务在 *** 作数据时,期间不会有其他事务进行干扰,能顺利完成事务 *** 作。
实现悲观锁
悲观锁解决方案非常简单,直接在 *** 作sql中加上for update 语句即可
update 表 set 列=值 where 条件列=值 for update select * from 表 where 条件列=值 for update
使用for update *** 作,可以认为是给每次 *** 作都加上表级别悲观锁,在事务没结束前,其他事务必须等待。
事务1
步骤1:启动事务
步骤2:使用悲观锁方式查询部门表(此时锁表)
步骤3:提交事务
事务2
在事务执行到步骤2时,执行下面逻辑,发现事务停滞,等待事务1commit之后才继续往下执行。
注意:并发环境下都不建议使用悲观锁,因为悲观锁容易锁表,导致事务等待,性能低下。
乐观锁
乐观锁 *** 作跟悲观锁区别在于不对 *** 作的数据表进行加锁,而是使用version字段去规避。
以部门表为例子
步骤1:给部门表添加version列,默认值为0
步骤2:实现乐观锁 *** 作
需求: 修改id=1数据sn字段改为:kfb
1>先查询
select id, name, sn, version from department where id = 1;
得到该数据列version = 0
2>再修改, 注意version版本更新
update department set sn = "kfb", version = version + 1 where id = 1 and version = 0
这里有2个注意要点:
1:更新 sn字段的同时,version列数据也跟随变动
2:更新sql 除了基本的id=1条件外,多了version = 0 条件。
为什么要这么设计? 原因:乐观锁 *** 作没有加锁,任意事务都可以同步 *** 作,多事务同时 *** 作,总有一个先成功,一成功则修改了version字段值,其他事务version 条件自然就不上啦,update失败。
步骤3:判断更新是否成功
乐观锁判断是否更新成功,就看执行update语句之后,返回的影响数据行数,如果行数大于0表示修改成功,如果行数等于0表示修改失败,放弃这次修改,一切重来。直到修改成功为止。
MyBatis-Plus版乐观锁MyBatis-Plus 使用@Version注解实现乐观锁
还是以部门表为例
步骤1:在部门表添加version字段
步骤2:部门实体对象添加version字段
public class Department { //省略其他字段 @Version private int version; }
步骤3:配置类中配置支持拦截器乐观锁
@Bean public MybatisPlusInterceptor optimisticLockerInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); return interceptor; }
步骤4:正常执行更新方法
@Test public void testUpdate(){ //先查询 Department dept = departmentMapper.selectById(1L); //再替换 dept.setId(1L); dept.setName("小卖部"); dept.setSn("sell"); //最后更新 departmentMapper.updateById(dept); }
执行后SQL
UPDATE department SET name=?, sn=?, version=? WHERe id=? AND version=?
MyBatis-Plus会自动讲乐观锁逻辑加载到sql中
使用Mybatis-Plus注意:
乐观锁支持的数据类型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime 仅支持 updateById(id) 与 update(entity, wrapper) 方法 另外,每次 *** 作前都是先查询,替换,再更新,否则乐观锁无效
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)