一次mysql死锁的发现
一次mysql死锁的发现
这篇文章主要介绍了笔者在业务扩展的时候,设计欠妥,导致的死锁,以及解决方案
本题难点在于下面这几部分:
INSERT并发执行:在DDB的RC事务下面的并发插入
INSERT、DELETE并发执行:
INTENTION LOCK产生的原因与前提:
INSERT并发执行
对于INSERT操作来说,若发生唯一约束冲突,则需要对冲突的唯一索引加上S Next-key Lock。从这里会发现,即使是RC事务隔离级别,也同样会存在Next-Key Lock锁,从而阻塞并发。
没有唯一主键的并发操作
表结构如下:
单次insert事务,并不提交,模拟并发提交情况
另起一事务,提交多次insert
可以发现事务非常顺利的被提交了,commit之后也发现数据很顺利的提交上来了
唯一主键的并发操作
表结构如下:
单次insert事务,不提交,模拟并发提交情况
另一个事务提交时,发现表锁
锁日志如下
INSERT、DELETE并发执行:
以无唯一主键表为例
表结构如下:
单次delete事务,不提交,模拟并发提交情况(非主键删除)
另一个事务执行insert的时候,发现表锁,(无论userId是否在删除队列里)
日志如下:
单次delete事务,不提交(主键删除)
另一个事务执行insert的时候,没有发现表锁,顺利提交
INTENTION LOCK产生的原因与前提:
INSERT INTENTION LOCK,翻译为插入意向锁,其实准确来说应该是INSERT INTENTION GAP LOCK。这个锁类型在老版本的InnoDB中并不存在,后来是为了优化插入性能而设计的。官方文档中的说明如下:
Prior to inserting the row, a type of gap lock called an insert intention gap lock is set. This lock signals the intent to insert in such a way that multiple transactions inserting into the same index gap need not wait for each other if they are not inserting at the same position within the gap.
在RC事务隔离级别下,由于插入大部分是不需要等待的,所以这把锁大部分时候也是不存在的。只有当发生锁等待时,即插入的这条记录下一条记录next_rec有锁,并且带有GAP属性,则这时需要对next_rec再加一个插入意向锁。由于插入意向锁和S/X Lock不兼容,因此需要等待。
在RC事务隔离级别下,虽然大多数插入操作是并发的,不会发生锁等待。然而,由于唯一约束的存在,这时就需要加上插入意向锁。而这也是上次死锁案例问题产生的原因。