“乐观锁”这个词以前我也没听过。上次在测试需求的时候,查询数据库发现有一个version字段,于是请教开发这个字干嘛使,人家回复我:乐观锁,结局并发更新用的。

当时大家都忙,咱也不敢多问。

今天就来折腾一下“乐观锁”。

一、什么是乐观锁

乐观锁其实用一句话来形容其作用就是:当要更新一条记录的时候,希望这条记录没有被别人更新,从而实现线程安全的数据更新。

结合下场景,记得那

是一张库存表,有一个字段记录商品库存,涉及多个地方都有可能去更新它:

  1. 程序A 查询到了这条数据,得到库存是800,准备+200更新成1000,但是还没更新。

  2. 程序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】什么是乐观锁?如何实现“乐观锁”相关推荐

  1. mysql 乐观锁 命令_MySQL-乐观锁

    悲观锁并不是适用于任何场景,它也有它存在的一些不足,因为悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性.如果加锁的时间过长,其他用户长时间无法访问,影响了程序的并发访问性,同时这 ...

  2. mysql内置乐观锁吗_mysql 乐观锁详解

    乐观锁: 乐观锁( Optimistic Locking ) 相对悲观锁而言,乐观锁机制采取了更加宽松的加锁机制.悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性.但随之而来的就是 ...

  3. Java 中15种锁的介绍:公平锁,可重入锁,独享锁,互斥锁,乐观锁,分段锁,自旋锁等等...

    http://blog.51cto.com/13919357/2339446 Java 中15种锁的介绍 在读很多并发文章中,会提及各种各样锁如公平锁,乐观锁等等,这篇文章介绍各种锁的分类.介绍的内容 ...

  4. 详解各种锁:CAS、共享锁、排它锁、互斥锁、悲观锁、乐观锁、行级锁、表级锁、页级锁、死锁、JAVA对CAS的支持、ABA问题、AQS原理

    共享锁(S锁) 又称为读锁,可以查看但无法修改和删除的一种数据锁.如果事务T对数据A加上共享锁后,则其他事务只能对A再加共享锁,不能加排它锁.获准共享锁的事务只能读数据,不能修改数据. 共享锁下其它用 ...

  5. 线程调度、公平锁和非公平锁、乐观锁和悲观锁、锁优化、重入锁

    1. 线程调度 线程调度指的就是给线程分配使用处理器的过程.主要的调度方式有两种:协同式调度和抢占式调度. 1.1 协同式调度 线程完成自己的任务之后主动通知系统切换到另一个线程上. 优点: 实现简单 ...

  6. 并发编程中常见的锁机制:乐观锁、悲观锁、CAS、自旋锁、互斥锁、读写锁

    文章目录 乐观锁 VS 悲观锁 悲观锁 乐观锁 CAS CAS机制 ABA问题 CAS的优缺点 互斥锁 VS 自旋锁 互斥锁 自旋锁 对比及应用场景 读写锁 实现方式 读写锁 VS 互斥锁 乐观锁 V ...

  7. mysql默认乐观锁悲观锁_MySQL中悲观锁和乐观锁到底是什么?-阿里云开发者社区...

    索引和锁是数据库中的两个核心知识点,隔离级别的实现都是通过锁来完成的 按照锁颗粒对锁进行划分 ? 锁用来对数据进行锁定,我们可以从锁定对象的粒度大小来对锁进行划分,分别为行锁.页锁和表锁. 行锁就是按 ...

  8. mysql中的乐观锁_MySQL中悲观锁和乐观锁到底是什么?

    索引和锁是数据库中的两个核心知识点,隔离级别的实现都是通过锁来完成的 按照锁颗粒对锁进行划分 ? 锁用来对数据进行锁定,我们可以从锁定对象的粒度大小来对锁进行划分,分别为行锁.页锁和表锁.行锁就是按照 ...

  9. [Todo] 乐观悲观锁,自旋互斥锁等等

    乐观锁.悲观锁.要实践 http://chenzhou123520.iteye.com/blog/1860954 <mysql悲观锁总结和实践> http://chenzhou123520 ...

  10. 程序员过关斩将--数据库的乐观锁和悲观锁并非真实的锁

    菜菜哥,告诉你一个消息 你有男票啦? 非也非也,我昨天出去偷偷面试,结果又挂了 哦,看来公司是真的不想让你走呀 面试官让我说一下乐观锁和悲观锁,我没回答上来,回来之后我查了,数据库没有这两种锁呀 了解 ...

最新文章

  1. c++ max 的头文件_学用C/C++编写小游戏程序(2.2 打字练习游戏)
  2. next_permutation(start,end)
  3. [集合]线程安全的HashMap
  4. 使用cgroup对指定用户使用的memory进行限制的一个具体例子
  5. bootstrap checkbox_[推荐]icheck-bootstrap(漂亮的ckeckbox/radiobox)
  6. import maven project很慢_你确定 Maven 相关的东西全部了解吗?
  7. DropDownList 数据绑定
  8. Mysql之无法查询中文字解决办法
  9. 「堡垒之夜」母公司Epic元宇宙蓝图:颠覆Facebook的社交媒体,拆除苹果的高墙花园...
  10. 9.1 交易数据的存储
  11. Validation 全注解+使用示例+官方文档
  12. go html桌面,用 Go 开发桌面应用程序(GUI):Webview、Lorca 与 Electron
  13. SpringClude--feign介绍
  14. 短视频平台开发,将图片、视频保存到本地的相册中
  15. qq互联登录授权php配置,php如何整合qq互联登录
  16. MySQL【触发器】
  17. Webpack 中 CSS 压缩插件
  18. html5网页中用video标签无法播放MP4视频的解决方法
  19. rtmp协议在p2p流媒体系统中的应用(论文转载)
  20. 实验室易发事故LS类型及防范方法

热门文章

  1. GTS--阿里巴巴分布式事务全新解决方案
  2. ByteBuf的源码分析
  3. C++学习笔记:(二)函数重载 常量与引用
  4. DevC++怎么更改背景颜色
  5. 【简单数论】H - A^X mod P_HRBUST - 2049_31行代码AC
  6. 【测试点分析】1067 试密码 (20分)_20行代码AC
  7. 19行代码AC——例题 6-2 铁轨(Rails, UVa 514)——解题报告
  8. mysql 关联查询_响应时间长?MySQL查询优化教程来了!
  9. 贵州轻工职业技术学院计算机分数,贵州轻工职业技术学院历年分数线 2021贵州轻工职业技术学院录取分数线...
  10. 25个优秀的Ajax技术和实例