【mybatis-plus】什么是乐观锁?如何实现“乐观锁”
“乐观锁”这个词以前我也没听过。上次在测试需求的时候,查询数据库发现有一个version字段,于是请教开发这个字干嘛使,人家回复我:乐观锁,结局并发更新用的。
当时大家都忙,咱也不敢多问。
今天就来折腾一下“乐观锁”。
一、什么是乐观锁
乐观锁其实用一句话来形容其作用就是:当要更新一条记录的时候,希望这条记录没有被别人更新,从而实现线程安全的数据更新。
结合下场景,记得那
是一张库存表,有一个字段记录商品库存,涉及多个地方都有可能去更新它:
程序A 查询到了这条数据,得到库存是800,准备+200更新成1000,但是还没更新。
程序B 也查询到了这条数据,得到库存是800,准备-200更新成600,并且提交更新了。
那么,这时候A再提交更新之后,B就会发现明明是自己是800-200=600,怎么最后变成了1000?
这就是因为A的事务导致了B的数据更新丢失。
文字可能读起来比较晦涩,有请灵魂画手:
正常情况下:
按先后顺序是, A先更新成1000,然后B再拿1000-200,更新成800,这样B就没异议了。
或者实在要2个同时更新,那也只能有一个成功,这样也没异议。
二、MP来实现乐观锁
乐观锁的实现,通过增加一个字段,比如version,来记录每次的更新。
查询数据的时候带出version的值,执行更新的时候,会再去比较version,如果不一致,就更新失败。
还是用之前的user表,增加了新的字段version
。
1.在实体类里增加对于的字段,并且加上自动填充(你也可以每次手动填充)
@Data
public class User {@TableId(type = IdType.ID_WORKER)private Long id;private String name;private Integer age;private String email;@TableField(fill = FieldFill.INSERT) // 新增的时候填充数据private Date createTime;@TableField(fill = FieldFill.INSERT_UPDATE) // 新增或修改的时候填充数据private Date updateTime;@TableField(fill = FieldFill.INSERT)@Versionprivate Integer version; // 版本号
}
@Component //此注解表示 将其交给spring去管理
public class MyMetaObjectHandler implements MetaObjectHandler {@Overridepublic void insertFill(MetaObject metaObject) {this.setFieldValByName("createTime", new Date(), metaObject);this.setFieldValByName("updateTime", new Date(), metaObject);this.setFieldValByName("version", 0, metaObject); //新增就设置版本值为0}@Overridepublic void updateFill(MetaObject metaObject) {this.setFieldValByName("updateTime", new Date(), metaObject);}
}
2. 配置插件
为了便于管理,可以见一个包,用于存放各种配置类,顺便把配置在启动类里的mapper扫描也换到这里来。
package com.pingguo.mpdemo.config;import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
// 配置扫描mapper的路径
@MapperScan("com.pingguo.mpdemo.mapper")
public class MpConfig {// 乐观锁插件@Beanpublic OptimisticLockerInterceptor optimisticLockerInterceptor() {return new OptimisticLockerInterceptor();}
}
3.测试乐观锁
先新增一条测试数据:
// 新增@Testvoid addUser() {User user = new User();user.setName("大周");user.setAge(22);user.setEmail("laowang@123.com");userMapper.insert(user);}
新增成功,可以看到version值是0。
再来试一下正常的修改:
// 测试乐观锁@Testvoid testOptimisticLocker() {User user = userMapper.selectById(1342502561945915393L);user.setName("大周2");userMapper.updateById(user);}
修改成功,可以看到version 变成了1。
最后,模拟下并发更新,乐观锁更新失败的情况:
// 测试乐观锁-失败@Testvoid testOptimisticLockerFailed() {User user = userMapper.selectById(1342502561945915393L);user.setName("大周3");User user2 = userMapper.selectById(1342502561945915393L);user2.setName("大周4");userMapper.updateById(user2); // 这里user2插队到user前面,先去更新userMapper.updateById(user); // 这里由于user2先做了更新后,版本号不对,所以更新失败}
按照乐观锁的原理,user2是可以更新成功的,也就是name会修改为“大周4”,version会加1。user因为前后拿到的版本号不对,更新失败。
结果符合预期,我们也可以看下mybatis的日志,进一步了解一下:
可以看到上面首先是2个查询,查询到的version都是1。
接着,第一个执行update语句的时候,where条件中version=1,可以找到数据,于是更新成功,切更新version=2。
ps:这里图丢了一个我重新补的一个数据,说明下意思,忽略ID与上面的不一致。
而第二个再执行update的时候,where条件version=1,已经找不到了,因为version已经被上面的更新成了2,所以更新失败。
【mybatis-plus】什么是乐观锁?如何实现“乐观锁”相关推荐
- mysql 乐观锁 命令_MySQL-乐观锁
悲观锁并不是适用于任何场景,它也有它存在的一些不足,因为悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性.如果加锁的时间过长,其他用户长时间无法访问,影响了程序的并发访问性,同时这 ...
- mysql内置乐观锁吗_mysql 乐观锁详解
乐观锁: 乐观锁( Optimistic Locking ) 相对悲观锁而言,乐观锁机制采取了更加宽松的加锁机制.悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性.但随之而来的就是 ...
- Java 中15种锁的介绍:公平锁,可重入锁,独享锁,互斥锁,乐观锁,分段锁,自旋锁等等...
http://blog.51cto.com/13919357/2339446 Java 中15种锁的介绍 在读很多并发文章中,会提及各种各样锁如公平锁,乐观锁等等,这篇文章介绍各种锁的分类.介绍的内容 ...
- 详解各种锁:CAS、共享锁、排它锁、互斥锁、悲观锁、乐观锁、行级锁、表级锁、页级锁、死锁、JAVA对CAS的支持、ABA问题、AQS原理
共享锁(S锁) 又称为读锁,可以查看但无法修改和删除的一种数据锁.如果事务T对数据A加上共享锁后,则其他事务只能对A再加共享锁,不能加排它锁.获准共享锁的事务只能读数据,不能修改数据. 共享锁下其它用 ...
- 线程调度、公平锁和非公平锁、乐观锁和悲观锁、锁优化、重入锁
1. 线程调度 线程调度指的就是给线程分配使用处理器的过程.主要的调度方式有两种:协同式调度和抢占式调度. 1.1 协同式调度 线程完成自己的任务之后主动通知系统切换到另一个线程上. 优点: 实现简单 ...
- 并发编程中常见的锁机制:乐观锁、悲观锁、CAS、自旋锁、互斥锁、读写锁
文章目录 乐观锁 VS 悲观锁 悲观锁 乐观锁 CAS CAS机制 ABA问题 CAS的优缺点 互斥锁 VS 自旋锁 互斥锁 自旋锁 对比及应用场景 读写锁 实现方式 读写锁 VS 互斥锁 乐观锁 V ...
- mysql默认乐观锁悲观锁_MySQL中悲观锁和乐观锁到底是什么?-阿里云开发者社区...
索引和锁是数据库中的两个核心知识点,隔离级别的实现都是通过锁来完成的 按照锁颗粒对锁进行划分 ? 锁用来对数据进行锁定,我们可以从锁定对象的粒度大小来对锁进行划分,分别为行锁.页锁和表锁. 行锁就是按 ...
- mysql中的乐观锁_MySQL中悲观锁和乐观锁到底是什么?
索引和锁是数据库中的两个核心知识点,隔离级别的实现都是通过锁来完成的 按照锁颗粒对锁进行划分 ? 锁用来对数据进行锁定,我们可以从锁定对象的粒度大小来对锁进行划分,分别为行锁.页锁和表锁.行锁就是按照 ...
- [Todo] 乐观悲观锁,自旋互斥锁等等
乐观锁.悲观锁.要实践 http://chenzhou123520.iteye.com/blog/1860954 <mysql悲观锁总结和实践> http://chenzhou123520 ...
- 程序员过关斩将--数据库的乐观锁和悲观锁并非真实的锁
菜菜哥,告诉你一个消息 你有男票啦? 非也非也,我昨天出去偷偷面试,结果又挂了 哦,看来公司是真的不想让你走呀 面试官让我说一下乐观锁和悲观锁,我没回答上来,回来之后我查了,数据库没有这两种锁呀 了解 ...
最新文章
- c++ max 的头文件_学用C/C++编写小游戏程序(2.2 打字练习游戏)
- next_permutation(start,end)
- [集合]线程安全的HashMap
- 使用cgroup对指定用户使用的memory进行限制的一个具体例子
- bootstrap checkbox_[推荐]icheck-bootstrap(漂亮的ckeckbox/radiobox)
- import maven project很慢_你确定 Maven 相关的东西全部了解吗?
- DropDownList 数据绑定
- Mysql之无法查询中文字解决办法
- 「堡垒之夜」母公司Epic元宇宙蓝图:颠覆Facebook的社交媒体,拆除苹果的高墙花园...
- 9.1 交易数据的存储
- Validation 全注解+使用示例+官方文档
- go html桌面,用 Go 开发桌面应用程序(GUI):Webview、Lorca 与 Electron
- SpringClude--feign介绍
- 短视频平台开发,将图片、视频保存到本地的相册中
- qq互联登录授权php配置,php如何整合qq互联登录
- MySQL【触发器】
- Webpack 中 CSS 压缩插件
- html5网页中用video标签无法播放MP4视频的解决方法
- rtmp协议在p2p流媒体系统中的应用(论文转载)
- 实验室易发事故LS类型及防范方法
热门文章
- GTS--阿里巴巴分布式事务全新解决方案
- ByteBuf的源码分析
- C++学习笔记:(二)函数重载 常量与引用
- DevC++怎么更改背景颜色
- 【简单数论】H - A^X mod P_HRBUST - 2049_31行代码AC
- 【测试点分析】1067 试密码 (20分)_20行代码AC
- 19行代码AC——例题 6-2 铁轨(Rails, UVa 514)——解题报告
- mysql 关联查询_响应时间长?MySQL查询优化教程来了!
- 贵州轻工职业技术学院计算机分数,贵州轻工职业技术学院历年分数线 2021贵州轻工职业技术学院录取分数线...
- 25个优秀的Ajax技术和实例