mysql rec gap_记一次mysql死锁解析

从日志中我们可以看出死锁发生在表T_ORDERBILL_TASK上而且是两条相同类型的针对表T_ORDERBILL_TASK插入的insert语句!检查T_ORDERBILL_TASK表结构如下:

136be34314a57ba454d97dfa8ef5d707.png

可见ORG_CODE上有二级索引。

(1) TRANSACTION也就是第一个事务的信息中:

lWAITING FOR THIS LOCK TO BE GRANTED,表示的是这个事务在等待的锁信息;

lindex ORG_CODE of table `T_BSE_QUERY_SCHEME`.`T_ORDERBILL_TASK`表示等的是表T_ORDERBILL_TASK上ORG_CODE索引上面的锁;

llock_mode X locks gap before rec insert intention waiting Record lock 表示这个语句要加一个插入意向锁但是还在等待状态,Record lock说明这是一个记录锁。

(2) TRANSACTION 也就是第二个事务中:

l(2) HOLDS THE LOCK(S)中lock_mode X locks gap before rec 表示了持有GAP锁

l(2) WAITING FOR THIS LOCK TO BE GRANTED中lock_mode X locks gap before rec insert intention waiting同(1)TRANSACTION等待加插入意向锁

结合业务开发提供的该模块儿的业务逻辑和发生死锁时间上下文业务日志可以整理出事务1和事务2的执行顺序为:

136be34314a57ba454d97dfa8ef5d707.png

或者

136be34314a57ba454d97dfa8ef5d707.png

可以看出在插入一条数据前先执行当前读锁住该条数据,若不存在则插入该条数据,否则执行update。

由于索引是顺序存储的,查出110026介于110019和110036之间:

由此可知:

当session 1执行select … for update当前读,由于ORG_CODE = 110026的数据不存在,因此会加上gap锁(110019,110036)。

Session 2执行select … for update当前读,同样也会加上gap锁(110019,110036),由于gap锁不互斥,所以该语句也可成功执行。

但是到第三步时无论是session 1先插入还是session 2先插入都会等待对方的gap锁,第四步时后插入的也会被对方的gap锁阻塞。两个session进入互相等待状态形成死锁,最后死锁检测将session2回滚。

[

结论

]

其实GAP锁,就是RR隔离级别相对于RC隔离级别不会出现幻读的关键。在RR隔离级别下,条件列上为非唯一索引时,当前读通过条件列未定位到满足条件的记录时会加GAP锁,保证后续的insert不能插入相同值的数据,以防止出现幻读。需要注意的是GAP锁并不互斥但是和插入意向锁互斥。相同语句的情况下RR模式由于会加GAP锁可能锁住更多的数据,虽然防止了幻读,但是会影响一定的并发。在配置RC和RR隔离级别的时候一定要根据业务场景进行选择。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值