• 进入"运维那点事"后,希望您第一件事就是阅读“关于”栏目,仔细阅读“关于Ctrl+c问题”,不希望误会!

MySQL RR隔离级别死锁问题剖析

MySQL 彭东稳 6年前 (2018-09-26) 33303次浏览 已收录 15个评论

本案例在RR隔离级别下,模拟数据如下:

下面操作发生死锁:

TRX-1 TRX-2
begin;
delete from ty where a=5;
begin;
delete from ty where a=5;#–等待TRX-1的X Lock –#
insert into ty(a,b) values(2,10);#– 等待TRX-2的 –# ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

来分析一下死锁产生的原因:

本死锁的堵塞主要集中在二级索引中,我们将二级索KEY idxa (a)和主键的数据按照InnoDB引擎存储的方式大概排列一下则如图:

MySQL RR隔离级别死锁问题剖析

TRX-1:delete from ty where a=5

产生的锁信息如下,记得打开 innodb_status_output_locks 参数。

根据这个记录我们可以画图如下,红色部分为锁定的部分箭头为Gap Lock:

MySQL RR隔离级别死锁问题剖析

TRX-2:delete from ty where a=5

此时 TRX-2 产生阻塞,等待 TRX-1 的锁。所信息如下:

从日志里我们可以看到 TRX-2 当前正在执行delete from test where a = 5,该条语句正在申请索引 idxa 的X锁,所以提示lock_mode X waiting。

根据这个记录我们可以画图如下,黄色部分为事务 TRX-2 准备上锁但是被堵塞的部分,包含黄色部分和红色部分的记录说明它既被 TRX-1 锁定了,并且 TRX-1 拿不到这条记录的锁,它实际上就是一个next key lock的堵塞:

MySQL RR隔离级别死锁问题剖析

TRX-1:insert into ty(a,b) values(2,10)

则会发生死锁,实际上这一条记录在二级索引的值为(2,11),11是主键的值,自增的。这里 insert 会申请一把 LOCK_INSERT_INTENTION(插入意向锁)。

INSERT INTENTION LOCK是GAP锁的一种,在事务执行 insert 的时候会申请一把插入意向锁(Insert Intention Lock)。在多事务并发写入不同数据记录至同一索引间隙的时候,并不需要等待其他事务完成,不会发生锁等待。例如当前索引上有记录4和8,两个并发session同时插入记录6,7。他们会分别为(4,8)加上GAP锁,但相互之间并不冲突(因为插入的记录不冲突)。

但这把锁并非每次插入需要加的。另外,在RC事务隔离级别下,由于插入大部分是不需要等待的,所以这把锁大部分时候也是不存在的。只有当发生锁等待时,即插入的这条记录的下一条记录(next_rec)有锁,并且带有GAP属性时,则需要对next_rec再加一个插入意向锁。由于插入意向锁和S/X Lock不兼容,因此需要等待。

很明显,这里 insert 操作会申请 INSERT INTENTION LOCK,并会产生等待,画图如下:

MySQL RR隔离级别死锁问题剖析

这里 insert 产生等待也就意味着 TRX-1 被堵塞,然后因为这个区域 TRX-2 也处于堵塞下,则会发生死锁(对同一个对象加锁是需要排序等待的,但在堵塞队列已经有 TRX-2 了,所以 TRX-1 这个GAP锁是拿不到的,此时就形成了 TRX-2 等待 TRX-1,TRX-1 也等待 TRX-2,产生循环等待)。死锁记录如下:

从死锁日志可以看出, (1) TRANSACTION 在等待 (5, 9) 的 X 锁,而 (2) TRANSACTION 持有  (5, 9) 的 X 锁,同时也等待  (5, 9) 的 X 锁,这里肯定就是在阻塞队列里面等待 (1) TRANSACTION 了,因为它不可能在同一个事务中等待自己持有的  (5, 9) 的 X 锁。所以可以看出两个事务产生了循环等待,死锁出现。

关于死锁信息如何阅读,参考“MySQL InnoDB锁信息阅读”。

这一步如果是:insert into ty(a,b) values(5,10),则不会发生死锁,实际上这一条记录记录在二级索引的值为(5,11),11是主键的值,则画图如下:

MySQL RR隔离级别死锁问题剖析

如果是这种情况,不会发生死锁,我们可以看到对于二级索引而言这个区域没有其他事务堵塞,只是 TRX-1 最开始获取过,本事务再次获取不会有问题。

本案例实际上就是看最后触发死锁的插入操作插入的记录到底落在二级索引的哪个区域。

<原文>

https://www.jianshu.com/p/4c9f800763de


如果您觉得本站对你有帮助,那么可以支付宝扫码捐助以帮助本站更好地发展,在此谢过。
喜欢 (293)
[资助本站您就扫码 谢谢]
分享 (0)

您必须 登录 才能发表评论!

(15)个小伙伴在吐槽