作者:胡呈清

爱可生 DBA 团队成员,善于故障剖析、性能优化,集体博客:https://www.jianshu.com/u/a95...,欢送探讨。

本文起源:原创投稿

*爱可生开源社区出品,原创内容未经受权不得随便应用,转载请分割小编并注明起源。


重要改良

MySQL8.0 的死锁日志能够看到事务1持有的锁信息了:

这对咱们剖析死锁无疑是个很好的帮忙,而在 MySQL5.7 是没有这个信息的,始终饱受诟病:

注意事项

然而这在某些状况下可能会产生一些误会,比方事务1持有锁和期待锁是同一个锁:

为什么会呈现这种状况?这是不是bug?

必须不是bug,咱们来复现这一死锁场景:

##设置RC隔离级别CREATE TABLE `t2` (  `c1` int(11) NOT NULL,  `c2` int(11) DEFAULT NULL,  PRIMARY KEY (`c1`),  UNIQUE KEY `c2` (`c2`));insert into t2 values(1,1),(5,4),(20,20);

死锁逻辑:

  1. session2 插入胜利,对 c2 索引 10 这一记录加 X Lock,即死锁日志中的lock_mode X locks rec but not gap;
  2. session1 插入时,产生惟一键抵触,须要对 c2 索引 10 这一记录加 S Lock,带 gap 属性,即锁的范畴为 (4,10]。然而因为 session2 曾经对记录加了 X Lock,与 S Lock 互斥,所以必须期待 session 2 先开释锁,也就是死锁日志中的lock mode S waiting;
  3. session2 再次插入 9,在 (4,10] 范畴内,这个地位有 session1 的 gap 锁(尽管还在锁队列中,没有加上),插入意向锁会被 gap 锁阻塞,即死锁日志中的 lock_mode X locks gap before rec insert intention waiting。session1、session2 相互期待,所以造成死锁。

session1 期待获取的锁 S Lock 阻塞了 session2 将要获取的锁,这在 MySQL8.0 中就会显示成 session1 持有的锁,同时也是 session1 期待的锁。就是这样。