MySQL间隙锁死锁问题

一、场景还原

当时同事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,在可重复读这种隔离级别下一起工作避免幻读。

四、如何关闭间隙锁(强烈不建议关闭)

1、降低隔离级别,例如降为提交读。

2、直接修改my.cnf,将开关,innodb_locks_unsafe_for_binlog改为1,默认为0即开启

五、还原线上间隙锁死锁的场景

5.1 复现

  • 5
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值