一、场景还原
当时同事A在线上代码中使用了Mybatis-plus的如下方法
com.baomidou.mybatisplus.extension.service.IService saveOrUpdate(T, com.baomidou.mybatisplus.core.conditions.Wrapper<T>)
该方法先执行了update操作,如果更新到就不再执行后续操作,如果没有更新到,才进行主键查询,查询到了就修改,未查询到就新增。具体方法如下
/**
* <p>
* 根据updateWrapper尝试更新,否继续执行saveOrUpdate(T)方法
* 此次修改主要是减少了此项业务代码的代码量(存在性验证之后的saveOrUpdate操作)
* </p>
*
* @param entity 实体对象
*/
default boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper) {
return update(entity, updateWrapper) || saveOrUpdate(entity);
}
那么这个方法的做法,为什么会导致间隙锁死锁呢?咱们一起来分析并还原间隙锁死锁的场景。
二、什么是间隙锁
间隙锁是MySQL行锁的一种,与行锁不同的是间隙锁可能锁定的是一行数据,也可能锁住一个间隙。锁定规则如下:
-
当修改的数据存在时,间隙锁只会锁定当前行。
-
当修改的数据不存在时,间隙锁会向左找第一个比当前索引值小的值,向右找第一个比当前索引值大 的值(没有则为正无穷),将此区间锁住,从而阻止其他事务在此区间插入数据。
三、间隙锁的作用
与行锁(例如乐观锁高级实现,MVCC)组合成Next-key lock,在可重复读这种隔离级别下一起工作避免幻读。
MySQL间隙锁与死锁解析

本文详细介绍了MySQL中的间隙锁,分析了间隙锁在防止幻读中的作用,以及其可能导致的死锁问题。通过场景还原,展示了在特定操作下如何产生间隙锁死锁,并通过实验验证了间隙锁的加锁特性,包括加锁非互斥性和仅锁定存在数据的行。
最低0.47元/天 解锁文章
420





