LambdaUpdateWrapper乐观锁update失败问题

简介: LambdaUpdateWrapper复用导致乐观锁失效产生的失败

背景

由于项目集成了Mybatis-Plus,所以更新语句就自然采用了LambdaUpdateWrapper来构造更新条件,使用 update(T entity, Wrapper\<T> updateWrapper)执行更新语句。由于此处逻辑借用CAS思想,利用乐观锁版本号来滚动更新。但是代码部署后发现滚动了3次更新都失败了。

问题复现

问题代码逻辑如下:

LambdaUpdateWrapper<People> updateWrapper = Wrappers.lambdaUpdate();
updateWrapper
        .eq(People::getId, people.getId())
        .eq(People::getDisable, 1);
boolean update;
int i = 0;
do {
    update = iPeopleService.update(new People()
                                    .setMoney(100)
                                    .setVersion(people.getVersion()),updateWrapper);
    if (!update) {
        log.info("更新人口钱数失败,滚动更新次数:{}", i);
        people = iPeopleService.getById(people.getId());
        i++;
    }
} while (!update && i < 3);

当开启sql日志后,发现三次执行得update语句分别如下:

--第一次执行sql,此条失败的原因是version版本号不对
UPDATE people SET money=?, version=? WHERE id = ? AND disable = ? AND version = ?;
--第二次执行sql,更新版本号后,此条失败的原因是where条件不对,莫名多出了一个version
UPDATE people SET money=?, version=? WHERE id = ? AND disable = ? AND version = ? AND version = ?;
--第三次执行sql,居然又多出了一个version
UPDATE people SET money=?, version=? WHERE id = ? AND disable = ? AND version = ? AND version = ? AND version = ?;

大概问题是发现了点,就去查问题所在,最终在官网看到下面一段话:
image.png

而我们的代码不就是因为复用了wrapper了吗,知道问题后我们及时调整逻辑如下:

boolean update;
int i = 0;
do {
    LambdaUpdateWrapper<People> updateWrapper = Wrappers.lambdaUpdate();
    updateWrapper
        .eq(People::getId, people.getId())
        .eq(People::getDisable, 1);
    update = iPeopleService.update(new People()
                                    .setMoney(100)
                                    .setVersion(people.getVersion()),updateWrapper);
    if (!update) {
        log.info("更新人口钱数失败,滚动更新次数:{}", i);
        people = iPeopleService.getById(people.getId());
        i++;
    }
} while (!update && i < 3);

代码调整之后测试了几遍发现功能正常了。

总结

  1. update(T entity, Wrapper\<T> updateWrapper)方法中,updateWrapper不能复用!!!
  2. api调用时一定要先详看官网,理清来龙去脉后再使用可以避免很多坑!!!
相关文章
|
SQL 关系型数据库 MySQL
INSERT ... FOR UPDATE这把锁你用过没?
INSERT ... FOR UPDATE这把锁你用过没?
286 0
|
SQL Java 数据库连接
Mybatis:通过on duplicate key update实现批量插入或更新
Mybatis:通过on duplicate key update实现批量插入或更新
2852 0
|
6月前
|
关系型数据库 MySQL 数据库
MySQL 并发 insert on duplicate key 导致的死锁
一 前言死锁,其实是一个很有意思也很有挑战的技术问题,大概每个DBA和部分开发同学都会在工作过程中遇见 。关于死锁我会持续写一个系列的案例分析,希望能够对想了解死锁的朋友有所帮助。二 案例分析2.1 业务场景业务方的目的是使用insert on duplicate key update对重复存在的记...
880 0
MySQL 并发 insert on duplicate key 导致的死锁
|
SQL 关系型数据库 MySQL
当并发insert on duplicate key update遇见死锁:更新丢失
数据库死锁问题,是一个老生常谈且很常见的问题,网上也有非常多对于各类死锁场景的解析和复现,但凡和死锁有关,无外乎不涉及数据库隔离等级、索引、以及innodb锁等相关原因。但是我这个案例我搜遍了全网也没能找到比较相似情况。于是我想尽可能的复现出这种情况,找出死锁的原因,找出可能出现的隐患。问题的背景:我们的数据库中的发生死锁的表是具有”多列组合构建的唯一索引“(不包含
19372 4
|
6月前
|
SQL 关系型数据库 MySQL
MySQL insert 遇到delete 唯一键未提交导致死锁
一 前言死锁,其实是一个很有意思也很有挑战的技术问题,大概每个DBA和部分开发同学都会在工作过程中遇见 。关于死锁我会持续写一个系列的案例分析,希望能够对想了解死锁的朋友有所帮助二案例分析2.1 业务场景用户录入商品,应用程序会提前检查是否存在相同记录,如果有则先删除再插入;如果没有则直接插入。2....
303 0
|
6月前
|
SQL 监控 关系型数据库
MySQL 并发delete不存在记录申请gap锁导致死锁
一 前言死锁,其实是一个很有意思也很有挑战的技术问题,大概每个DBA都会在工作过程中遇见。关于死锁我会持续写一个系列的案例分析,希望能够对想了解死锁的朋友有所帮助。本文源于我们的生产案例:并发申请gap锁导致的死锁案例,与之前的 死锁案例一不同,本案例是因为RR模式下两个事务中的sql可以获取同一个...
188 0
|
6月前
|
SQL 关系型数据库 MySQL
MySQL 并发更新唯一键和插入数据导致死锁
一 前言死锁,其实是一个很有意思也很有挑战的技术问题,大概每个DBA和部分开发同学都会在工作过程中遇见 。关于死锁我会持续写一个系列的案例分析,希望能够对想了解死锁的朋友有所帮助。二 案例分析2.1 业务场景业务开发同学想同步数据,他们的逻辑是通过update 更新操作,如果更新记录返回的affec...
452 0
|
前端开发 关系型数据库 MySQL
三言两语记录mysql for update锁
另一个连接B 发起普通select请求,正常返回结果 3.连接B 发起select for update请求,由于第一个步骤的事务还没有结束,所以不能获取,会一直堵塞,直到超时 或者锁被释放后返回
249 0
|
SQL Java 数据库连接
mybatis-plus在更新数据时乐观锁version无效
今天在使用mybatis-plus乐观锁插件时,发现乐观锁并没有生效。 查了问题发现首先需要查询出结果(也就是需要version),然后再进行更新,这样乐观锁就能起作用了。