实现步骤

step1:添加乐观锁拦截器

MP的其他拦截器功能可以参考官网

  1. @Bean
  2. public MybatisPlusInterceptor mybatisPlusInterceptor() {
  3. MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
  4. interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
  5. return interceptor;
  6. }

step2:配置Entity

  1. @TableField(fill = FieldFill.UPDATE)
  2. @Version
  3. private Date updateTime;

用更新字段充当版本号。

  • 上面的配置需要注意的是:updateTime既配置自动填充,又配置了乐观锁功能。MP在进行处理时会先进行乐观锁处理,然后再进行自动填充。
  • 问题:前端送了id和一些需要更新的字段过来,每次需要从数据库中查出version,然后再进行更新(要么前端将版本号传过来);
  • 支持的数据类型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime;
  • 仅支持 updateById(id) 与 update(entity, wrapper) 方法,在 update(entity, wrapper) 方法下, wrapper 不能复用!!!
  • 对于updateTime这个字段,在数据库中建议设置成时区不相关的时间戳类型。

多说一点

使用updateTime作为版本号可能会存在一些问题。

我们通常需要将updateTime返回给前端页面,假如我们不做任何设置,返回前端的数据大概是下面的样子:

  1. {
  2. "userId": 367,
  3. "address": "上海市自由之路xxxxxx...",
  4. "workUnit": "XXXX",
  5. "createTime": "2020-12-22T00:00:00.000+08:00",
  6. "updateTime": "2021-01-08T17:28:14.782+08:00"
  7. }

这种时间格式可能不是前端页面需要的,这是我们可以进行如下设置;

  1. spring:
  2. jackson:
  3. default-property-inclusion: non_null
  4. time-zone: GMT+8
  5. date-format: yyyy-MM-dd HH:mm:ss

返回的数据

  1. {
  2. "userId": 367,
  3. "address": "上海市自由之路xxxxxx...",
  4. "workUnit": "XXXX",
  5. "createTime":"2020-12-22 00:00:00",
  6. "updateTime":"2021-01-08 17:28:14"
  7. }

经过这个配置后,就可以得到可读性比较好的时间格式了。但是我们需要注意的时候,这个时间的精度其实已经丢失了,当前提交修改数据到后端,这个值和数据库中的值已经不相等了。所以永远不能将数据更新成功。

所以这种情况下使用updateTime来进行乐观锁更新就不太适合了。可以考虑在表中另外加一个字段version来进行乐观锁更新。

但其实还是有比较好的解决办法的。

首先,我们不要对返回的时间格式进行全局话配置。

  1. spring:
  2. jackson:
  3. default-property-inclusion: non_null
  4. time-zone: GMT+8
  5. # date-format: yyyy-MM-dd HH:mm:ss

然后,添加一个updateTime的备份字段updateTimeSimpleFormat,并对这个字段进行单独的时间格式化。

  1. private Date updateTime;
  2. @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
  3. private Date updateTimeSimpleFormat;

updateTimeSimpleFormat不要生成get和set方法,在updateTime的set方法中对updateTimeSimpleFormat进行赋值。

  1. public void setUpdateTime(Date updateTime) {
  2. this.updateTime = updateTime;
  3. this.updateTimeSimpleFormat = updateTime;
  4. }

这样就既能满足前端返回格式化的时间,后端又能获取到乐观锁的版本号。

但是,这个方法比较不好的地方,就是必须对每个时间格式进行@JsonFormat注解配置,不能进行全局配置,比较繁琐。

总结:使用updateTime作为乐观锁的优点就是不需要再新加字段,比较简洁。但是带来的问题上面已经讲的很清楚了。还是印证了那个真理:没有完美的技术,只有适合的技术。

MP(MyBatis-Plus)实现乐观锁更新功能的更多相关文章

  1. mybatis 如何使用乐观锁

    悲观锁的问题: 因为悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性.如果加锁的时间过长,其他用户长时间无法访问,影响了程序的并发访问性,同时这样对数据库性能开销影响也很大,特别是 ...

  2. 阶段3 1.Mybatis_12.Mybatis注解开发_3 mybatis注解开发保存和更新功能

    使用直接来实现CRUD操作 Insert方法 创建测试类 把变量都定义在外面 写测试方法 修改链接的数据库 update方法 再加上address 被更新的数据

  3. xorm - Update,乐观锁,更新时间updated,NoAutoTime()

    更新数据使用Update方法 Update方法的第一个参数为需要更新的内容,可以为一个结构体指针或者一个Map[string]interface{}类型. 当传入的为结构体指针时,只有非nil和非0的 ...

  4. 【mybatis-plus】什么是乐观锁?如何实现“乐观锁”

    "乐观锁"这个词以前我也没听过.上次在测试需求的时候,查询数据库发现有一个version字段,于是请教开发这个字干嘛使, 人家回复我:乐观锁,解决并发更新用的.当时大家都忙,咱也不 ...

  5. Mysql共享锁、排他锁、悲观锁、乐观锁及其使用场景

    一.相关名词 |--表级锁(锁定整个表) |--页级锁(锁定一页) |--行级锁(锁定一行) |--共享锁(S锁,MyISAM 叫做读锁) |--排他锁(X锁,MyISAM 叫做写锁) |--悲观锁( ...

  6. MySQL 乐观锁与悲观锁

    悲观锁 悲观锁(Pessimistic Lock),顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁. 悲观锁: ...

  7. 浅谈Mysql共享锁、排他锁、悲观锁、乐观锁及其使用场景

    浅谈Mysql共享锁.排他锁.悲观锁.乐观锁及其使用场景   Mysql共享锁.排他锁.悲观锁.乐观锁及其使用场景 一.相关名词 |--表级锁(锁定整个表) |--页级锁(锁定一页) |--行级锁(锁 ...

  8. Mysql共享锁、排他锁、悲观锁、乐观锁

    一.相关名词 |--表级锁(锁定整个表) |--页级锁(锁定一页) |--行级锁(锁定一行) |--共享锁(S锁,MyISAM 叫做读锁) |--排他锁(X锁,MyISAM 叫做写锁) |--间隙锁( ...

  9. 写了一个 gorm 乐观锁插件

    前言 最近在用 Go 写业务的时碰到了并发更新数据的场景,由于该业务并发度不高,只是为了防止出现并发时数据异常. 所以自然就想到了乐观锁的解决方案. 实现 乐观锁的实现比较简单,相信大部分有数据库使用 ...

随机推荐

  1. 记一次UE4源码编译和游戏项目打包过程

    1.首先我们需要注册一个Epic账户,网址如下 http://api.unrealengine.com/CHN/GettingStarted/Installation/index.html#bookm ...

  2. golang GMP goroutine调度器

    Goroutine可以动态的伸缩栈的大小,最小2-4kb,最大1GB

  3. 【eJOI2020】考试(dp & 树状数组优化)

    Description \(n\) 个正整数排成一列,每个位置 \(i\) 有一个初始值 \(A_i\) 以及目标值 \(B_i\). 一次操作可以选定一个区间 \([l, r]\),并将区间内所有数 ...

  4. JavaScript:浏览器的本地存储

    cookie.localStorage.sessionStorage的使用 <!DOCTYPE html> <html lang="en"> <hea ...

  5. Linux端口被占用解决

    有时候关闭软件后,后台进程死掉,导致端口被占用.下面以JBoss端口8083被占用为例,列出详细解决过程. 解决方法: 1.查找被占用的端口 netstat -tln netstat -tln | g ...

  6. django 初始化项目 和modelviewset 使用

    django初始化项目 1.初始化项目结构└─shiyanlou_project │ .gitignore│ README.en.md # 英文│ README.md # 中文项目简介│├─celer ...

  7. css进阶 00-准备

    前言 css 进阶的主要内容如下. #1.css 非布局样式 html 元素的分类和特性 css 选择器 css 常见属性(非布局样式) #2.css 布局相关 css 布局属性和组合解析 常见布局方 ...

  8. Leetcode 220 周赛 题解

    5629. 重新格式化电话号码 模拟 注意一些细节,最后位置是否取值. class Solution { public: string reformatNumber(string number) { ...

  9. burpsuite进阶使用

    .Burpsuite:爆破 个人建议选择pro破解版的,免费版的太鸡肋,爆破不能设置线程,速度超乎你想像 浏览器和burpsuite设置代理后,开启抓包,截获数据包后,右键选择发送到repeater修 ...

  10. SpringBoot从入门到精通教程(五)

    上节,我们讲了 SpringBoot 如何使用MyBatis 今天我们讲讲 Springboot Logo自定义的问题, 我们在启动 SpringBoot 时,控制台会打印 SpringBoot Lo ...