乐观锁及mybatis-plus实现

乐观锁与悲观锁

乐观锁:在修改数据时,总是持乐观态度,认为数据不会被其他人修改,只在真正进行数据更新前进行数据冲突的检测。如果发生冲突,则将异常结果向上层反馈(比如数据库更新返回0代表无数据更新),由上层逻辑进行处理。乐观锁适合读多写少的场景,可以提高程序的吞吐量。

悲观锁:在修改数据时,总是认为数据很可能会被其他人修改,所以在进行逻辑处理前,就对后续要更新的数据进行加锁,以防其他人对数据进行修改。实际上是使数据的变更操作转变成串行化的方式进行。悲观锁,具有强烈的独占和排他特性。

乐观锁的实现方式

版本号:为每条数据增加一个字段,记录该条数据的当前版本。当对数据进行更新前,先获取数据的版本号,更新时,检测数据库的版本号是否与先前获取的版本号一致,如果一致,则更新成功,否则更新失败。版本号一般使用自增序列或时间戳。但是使用时间戳时需要注意,当在极短的时间内有可能多条线程会同时更新成功,造成数据不一致。如时间戳精确到毫秒,在同一毫秒内多条线程进行数据更新,此时会都更新成功。使用版本号的方式适合读多写少的场景,写很少,数据冲突的概率就很低。

条件判断:在某些场景下,使用版本号的方式不一定适合。比如在电商应用扣减库存场景,由于在高并发下,同一时刻存在大量线程对库存进行扣减,此时很容易造成数据冲突(当前线程去更新数据时,有可能数据已经被其他线程修改,版本号发生了变更),导致只有一小部分的线程扣减库存成功,而大部分的线程无法扣减,下单失败,显然这是大家不想看到的。所以针对写多读少的场景,条件判断比较适合。条件判断,指在更新数据时,利用条件对数据进行检测,只有条件成立,才能更新成功,否则更新失败。比如扣库存场景,只要库存量充足,就应该扣减成功,所以条件就是库存量大于等于应扣数量,sql类似如下:update 库存表 set 库存量=库存量-扣减量 where id=商品id and 库存量≥扣减量。

乐观锁数据冲突处理办法

当数据库乐观锁检测到数据冲突时,一般反馈到应用的结果是更新数据为0条,应用可以根据是否为0进行处理,一般的处理方法有两种:
1、重试执行业务逻辑,重新提交事务;
2、抛出异常,事务回滚。

乐观锁的使用

分别说明基于版本号和基于条件的乐观锁使用。
项目环境:springboot+mysql+mybatis-plus+maven。

基于版本号的乐观锁使用

mybatis-plus插件提供了版本号方式的实现,只需要配置相应的拦截器和注解即可实现。通过拦截器对版本号进行更新。
一、项目准备
1、引入maven依赖

<dependency>
	<groupId>com.baomidou</groupId>
	<artifactId>mybatis-plus-boot-starter</artifactId>
	<version>3.4.2</version>
</dependency>

2、增加拦截器

@Configuration
public class BeanInitConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }
}

mybatis-plus-boot-starter依赖包在3.4.0以上,OptimisticLockerInterceptor已过期。所以在3.4.0及以下,应使用OptimisticLockerInterceptor:

@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor(){
	return new OptimisticLockerInterceptor();
}

3、实体增加version字段,并增加@Version注解
在这里插入图片描述4、编写Controller、Service、Mapper层
Controller:
在这里插入图片描述
Service:
在这里插入图片描述
Mapper:
在这里插入图片描述
5、数据库表
在这里插入图片描述
二、测试
1、新增测试
(1)、浏览器访问新增接口
在这里插入图片描述
可以看到,返回值为1,代表数据库发生1条记录变更。
(2)、查看数据库记录
在这里插入图片描述
可以看到,数据库已经新增了一条记录,而且version字段已经正确被赋值(数据库设置version默认值为0)。
2、更新测试
(1)、浏览器访问更新接口
在这里插入图片描述
同样发生一条数据变更。
(2)、查看数据库记录
在这里插入图片描述
可以看到,version字段已经发生变更。
(3)、执行sql情况
在这里插入图片描述
可以看到,在更新数据前先查询版本号,更新时mybatis-plus的拦截器自动将version进行自增。
(4)、异常测试:将获取到的版本号改成小于当前数据库的版本号,再进行更新
在这里插入图片描述
再次访问更新接口,此时可以看到后台报了异常,并且数据更新数为0,因为当待更新数据版本号小于数据库的版本号时无法进行更新数据,这正是乐观锁的作用
在这里插入图片描述
3、并发测试
Controller层启动两个线程同时更改数据,统计更新成功的次数,然后对比数据库的版本增量是否与统计成功的次数一致。
(1)、Controller层启动两个线程,每个线程运行5秒
在这里插入图片描述
(2)、数据库初始状态
在这里插入图片描述
(3)、页面访问更新接口,等待运行结束
在这里插入图片描述
(4)、后台日志打印
在这里插入图片描述
更新成功共895次。
(5)、数据库最终状态
在这里插入图片描述
可见823+895=1718。
4、说明
(1)、插入的时候version字段可以为空,数据库设置默认值,更新的时候version字段不可为空,否则无法进行自增,乐观锁不会生效。
(2)、如果不是用mybatis提供的mapper进行操作,而是手写的sql进行数据的更新,需要自己在sql拼version的更新:
在这里插入图片描述
(3)、UserServiceImpl的updateUser方法,在该方法内调用另一个Service(或dao层)进行数据更新,当提交User的事务,如果发现数据冲突抛出异常时事务进行回滚,另一个Service的事务也会回滚,保证了事务的一致性。
在这里插入图片描述

条件判断方式的乐观锁使用

以扣库存场景进行演示。

1、Controller、Service、Mapper、Entity:
Controller:
在这里插入图片描述
Service:
在这里插入图片描述
Mapper:
在这里插入图片描述
Entity:
在这里插入图片描述
2、数据库初始化数据
在这里插入图片描述
3、浏览器访问扣减库存接口
在这里插入图片描述
4、后台日志
在这里插入图片描述
5、更新后数据库情况
在这里插入图片描述
可以看到,两个线程所有的扣减都成功,而且数据库数据也正确,这是因为库存量足够,每次扣减都可成功。
6、手动将数据库库存量调为500,再次调用扣减接口
当前库存量:
在这里插入图片描述
调用扣减接口,查看后台日志和数据库数据:
在这里插入图片描述
数据库情况
在这里插入图片描述
可以看到,最多只能有500次扣减成功,之后的扣减都已经失败。

源码分析

mybatis-plus能实现版本号的更新,主要通过配置的OptimisticLockerInnerInterceptor拦截器实现,该拦截器会在sql执行前被调用,所以实现版本号的更新逻辑就在该拦截器内。
在这里插入图片描述
计算新值:
在这里插入图片描述
设置新值:
在这里插入图片描述

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
手把手视频详细讲解项目开发全过程,需要的小伙伴自行百度网盘下载,链接见附件,永久有效。 课程简介 MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。使用原生的Mybatis编写持久层逻辑时,所需要的代码是比较繁琐的,需要定义Mapper接口和Mapper.xml文件,每一个方法都需要编写对应的sql语句,会存在很多大量的重复工作,使用MP之后,对通用的方法做了高度的抽取,避免了很多重复工作,可以非常快速的实现了单表的各种增、删、改、查操作。除此之外,MP还提供了其他的高级功能,如:枚举、插件、ActiveRecord、SQL注入等。 本课程全面讲解了Mybatis-Plus框架的使用,从快速入门到原理分析再到插件的应用。每一个知识点都有案例进行演示学习,最终通过学习你将全面掌握MP的使用,从而使Mybatis的的开发更加的高效,达到事半功倍的效果。 适应人群 有一定的Java以及Mybatis框架的基础。 从0开始全面讲解Mybatis-Plus框架 l 快速入门 n Mybatis + MP 整合 n Spring + Mybatis + MP 整合 n SpringBoot + Mybatis + MP 整合 n 通用CRUD的全面讲解 n 配置 l 高级用法 n 条件构造器 n Oracle 主键Sequence n 通用枚举n ActiveRecord n 逻辑删除 l 插件 n 执行分析插件 n 性能分析插件 n 乐观锁插件 主讲内容 章节一:快速入门 1. Mybatis-Plus简介 2. 快速入门 3. 通用CRUD 4. 配置 5. 条件构造器 章节二:进阶 1. ActiveRecord 2. Oracle 主键Sequence 3. 插件 章节三:高级应用 1. Sql 注入器 2. 自动填充功能 3. 逻辑删除 4. 通用枚举 5. 代码生成器 6. MybatisX 快速开发插件

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乐观男孩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值