1、概念

在讲解乐观锁之前,我们还是先来分析下问题:

业务并发现象带来的问题:秒杀

  • 假如有100个商品或者票在出售,为了能保证每个商品或者票只能被一个人购买,如何保证不会出现超买或者重复卖

  • 对于这一类问题,其实有很多的解决方案可以使用

  • 第一个最先想到的就是锁,锁在一台服务器中是可以解决的,但是如果在多台服务器下锁就没有办法控制,比如12306有两台服务器在进行卖票,在两台服务器上都添加锁的话,那也有可能会导致在同一时刻有两个线程在进行卖票,还是会出现并发问题

  • 我们接下来介绍的这种方式是针对于小型企业的解决方案,因为数据库本身的性能就是个瓶颈,如果对其并发量超过2000以上的就需要考虑其他的解决方案了。

简单来说,乐观锁主要解决的问题是当要更新一条记录的时候,希望这条记录没有被别人更新。

2、实现思路

乐观锁的实现方式:

  • 数据库表中添加version列,比如默认值给1

  • 第一个线程要修改数据之前,取出记录时,获取当前数据库中的version=1

  • 第二个线程要修改数据之前,取出记录时,获取当前数据库中的version=1

  • 第一个线程执行更新时,set version = newVersion where version = oldVersion

    • newVersion = version+1 [2]

    • oldVersion = version [1]

  • 第二个线程执行更新时,set version = newVersion where version = oldVersion

    • newVersion = version+1 [2]

    • oldVersion = version [1]

  • 假如这两个线程都来更新数据,第一个和第二个线程都可能先执行

    • 假如第一个线程先执行更新,会把version改为2,

    • 第二个线程再更新的时候,set version = 2 where version = 1,此时数据库表的数据version已经为2,所以第二个线程会修改失败

    • 假如第二个线程先执行更新,会把version改为2,

    • 第一个线程再更新的时候,set version = 2 where version = 1,此时数据库表的数据version已经为2,所以第一个线程会修改失败

    • 不管谁先执行都会确保只能有一个线程更新数据,这就是MybatisPlus提供的乐观锁的实现原理分析。

上面所说的步骤具体该如何实现呢?

3、实现步骤

分析完步骤后,具体的实现步骤如下:

步骤1:数据库表添加列

列名可以任意,比如使用version,给列设置默认值为1

步骤2:在模型类中添加对应的属性

根据添加的字段列名,在模型类中添加对应的属性值

@Data
//@TableName("tbl_user") 可以不写是因为配置了全局配置
public class User {
   @TableId(type = IdType.ASSIGN_UUID)
   private String id;
   private String name;
   @TableField(value="pwd",select=false)
   private String password;
   private Integer age;
   private String tel;
   @TableField(exist=false)
   private Integer online;
   private Integer deleted;
   @Version
   private Integer version;
}
步骤3:添加乐观锁的拦截器
@Configuration
public class MpConfig {
   @Bean
   public MybatisPlusInterceptor mpInterceptor() {
       //1.定义MybatisPlus拦截器
       MybatisPlusInterceptor mpInterceptor = new MybatisPlusInterceptor();
       //2.添加乐观锁拦截器
       mpInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
       return mpInterceptor;
  }
}
步骤4:执行更新操作

添加version数据

@SpringBootTest
class Mybatisplus03DqlApplicationTests {

   @Autowired
   private UserDao userDao;    @Test
   void testUpdate(){
       User user = new User();
       user.setId(3L);
       user.setName("Jock666");
       user.setVersion(1);
       userDao.updateById(user);
  }
}

你会发现,我们传递的是1,MybatisPlus会将1进行加1,然后,更新回到数据库表中。

所以要想实现乐观锁,首先第一步应该是拿到表中的version,然后拿version当条件在将version加1更新回到数据库表中,所以我们在查询的时候,需要对其进行查询

@SpringBootTest
class Mybatisplus03DqlApplicationTests {

   @Autowired
   private UserDao userDao;    @Test
   void testUpdate(){
       //1.先通过要修改的数据id将当前数据查询出来
       User user = userDao.selectById(3L);
       //2.将要修改的属性逐一设置进去
       user.setName("Jock888");
       userDao.updateById(user);
  }
}

大概分析完乐观锁的实现步骤以后,我们来模拟一种加锁的情况,看看能不能实现多个人修改同一个数据的时候,只能有一个人修改成功。

@SpringBootTest
class Mybatisplus03DqlApplicationTests {

   @Autowired
   private UserDao userDao;    @Test
   void testUpdate(){
      //1.先通过要修改的数据id将当前数据查询出来
       User user = userDao.selectById(3L);     //version=3
       User user2 = userDao.selectById(3L);    //version=3
       user2.setName("Jock aaa");
       userDao.updateById(user2);              //version=>4
       user.setName("Jock bbb");
       userDao.updateById(user);               //verion=3?条件还成立吗?
  }
}

运行程序,分析结果:

乐观锁就已经实现完成了,如果对于上面的这些步骤记不住咋办呢?

参考官方文档来实现:https://baomidou.com/pages/0d93c0/#optimisticlockerinnerinterceptor

Java开发学习(四十九)----MyBatisPlus更新语句之乐观锁的更多相关文章

  1. Java开发学习(四十)----MyBatisPlus入门案例与简介

    一.入门案例 MybatisPlus(简称MP)是基于MyBatis框架基础上开发的增强型工具,旨在简化开发.提供效率. SpringBoot它能快速构建Spring开发环境用以整合其他技术,使用起来 ...

  2. Java开发学习(三十九)----SpringBoot整合mybatis

    一.回顾Spring整合Mybatis Spring 整合 Mybatis 需要定义很多配置类 SpringConfig 配置类 导入 JdbcConfig 配置类 导入 MybatisConfig ...

  3. Java开发学习(二十九)----Maven依赖传递、可选依赖、排除依赖解析

    现在的项目一般是拆分成一个个独立的模块,当在其他项目中想要使用独立出来的这些模块,只需要在其pom.xml使用<dependency>标签来进行jar包的引入即可. <depende ...

  4. Java开发学习(四十一)----MyBatisPlus标准数据层(增删查改分页)开发

    一.标准CRUD使用 对于标准的CRUD功能都有哪些以及MyBatisPlus都提供了哪些方法可以使用呢? 我们先来看张图: 1.1 环境准备 这里用的环境就是Java开发学习(四十)----MyBa ...

  5. Java开发学习(三十六)----SpringBoot三种配置文件解析

    一. 配置文件格式 我们现在启动服务器默认的端口号是 8080,访问路径可以书写为 http://localhost:8080/books/1 在线上环境我们还是希望将端口号改为 80,这样在访问的时 ...

  6. Java开发学习(二十四)----SpringMVC设置请求映射路径

    一.环境准备 创建一个Web的Maven项目 参考Java开发学习(二十三)----SpringMVC入门案例.工作流程解析及设置bean加载控制中环境准备 pom.xml添加Spring依赖 < ...

  7. Java开发学习(二十五)----使用PostMan完成不同类型参数传递

    一.请求参数 请求路径设置好后,只要确保页面发送请求地址和后台Controller类中配置的路径一致,就可以接收到前端的请求,接收到请求后,如何接收页面传递的参数? 关于请求参数的传递与接收是和请求方 ...

  8. Java开发学习(二十六)----SpringMVC返回响应结果

    SpringMVC接收到请求和数据后,进行了一些处理,当然这个处理可以是转发给Service,Service层再调用Dao层完成的,不管怎样,处理完以后,都需要将结果告知给用户. 比如:根据用户ID查 ...

  9. Java开发学习(二十八)----拦截器(Interceptor)详细解析

    一.拦截器概念 讲解拦截器的概念之前,我们先看一张图: (1)浏览器发送一个请求会先到Tomcat的web服务器 (2)Tomcat服务器接收到请求以后,会去判断请求的是静态资源还是动态资源 (3)如 ...

  10. Java开发学习(二十二)----Spring事务属性、事务传播行为

    一.事务配置 上面这些属性都可以在@Transactional注解的参数上进行设置. readOnly:true只读事务,false读写事务,增删改要设为false,查询设为true. timeout ...

随机推荐

  1. 巧用VBA实现:基于多个关键词模糊匹配Excel多行数据

    在用Excel处理实际业务中,我们会碰到如下场景: 1.从一堆人名中找到包含某些关键字的名字: 2.从银行流水文件中根据[备注]字段找到包含某些关键字的,统一识别为[手续费业务]等. 这本质说的都是一 ...

  2. Es 学习笔记 (1)

    目录 前言 什么是es? es数据组织类比 应用场景 核心概念 集群 节点(node) 索引(Index) 文档类型(Type) 文档(Document) Mapping 核心简单域类型 分片(sha ...

  3. bat批处理命令语法总结

    ::1. 关闭回显表示不显示命令本身只显示输出部分 @echo off ::2. 设置变量注意等号间不能有空格 set num=10 ::3. 使用变量 echo %num% ::4. call 调用 ...

  4. VS Code For Web 深入浅出 -- 导读篇

    下一代 IDE 的形态究竟是什么呢?VS Code For Web 试图回答这个问题. 背景 众所周知,VS Code 是当前工业界最优秀的代码编辑器之一.它由<设计模式>的作者 Eric ...

  5. 4.MongoDB系列之索引(一)

    1. 执行计划查看 db.getCollection('users').find({'username': 'shenjian'}).explain('executionStats') 结果查看,先大 ...

  6. tensorboard图表显示不全的问题

    之前跑bcq生成tensorboard文件的时候,有二十个点用来描图,然而后10个数据点总是不显示,之后将tensorboard换成tensorboardX便解决了问题. 比如 from torch. ...

  7. 深入浅出TCP与IP协议笔记

    TCP/IP 4层结构:应用层 传输层 网络层 链路层   探索过程问题:一个主机的数据要经过哪些过程才到达对方的主机上 一组电信号就是一个数据包,一个数据包称为一帧,制定这个规则的就是以太网协议   ...

  8. .Net Core 3.0 对 MongoDB 的多条件(两种)查询操作

    前言   在日常开发中,偶尔会用到 MongoDB 的数据操作,也花费了一些时间调试,因此在此处记录一下,共同进步. 废话少说,出招吧! 正文 2.1 准备工作 首先需要引入 .Net 平台链接 Mo ...

  9. Jenkins用户管理

    用户注册和权限管理介绍. 1. 用户注册 进入[系统管理]-[全局安全配置],进行配置: 1.1 安全域 选择[Jenkins专有用户数据库],勾选[允许用户注册],随后[保存] 1.2 用户注册 在 ...

  10. vue 使用vuex 刷新时保存数据

    created () { this.$store.replaceState(Object.assign(this.$store.state,JSON.parse(localStorage.getIte ...