一次mysql死锁的发现

一次mysql死锁的发现

这篇文章主要介绍了笔者在业务扩展的时候,设计欠妥,导致的死锁,以及解决方案

本题难点在于下面这几部分:

INSERT并发执行:在DDB的RC事务下面的并发插入
INSERT、DELETE并发执行:
INTENTION LOCK产生的原因与前提:

INSERT并发执行

对于INSERT操作来说,若发生唯一约束冲突,则需要对冲突的唯一索引加上S Next-key Lock。从这里会发现,即使是RC事务隔离级别,也同样会存在Next-Key Lock锁,从而阻塞并发。

没有唯一主键的并发操作

表结构如下:
一次mysql死锁的发现_第1张图片

单次insert事务,并不提交,模拟并发提交情况
一次mysql死锁的发现_第2张图片

另起一事务,提交多次insert
一次mysql死锁的发现_第3张图片

可以发现事务非常顺利的被提交了,commit之后也发现数据很顺利的提交上来了
一次mysql死锁的发现_第4张图片

唯一主键的并发操作

表结构如下:
一次mysql死锁的发现_第5张图片

单次insert事务,不提交,模拟并发提交情况
image.png

另一个事务提交时,发现表锁
image.png

锁日志如下
一次mysql死锁的发现_第6张图片

INSERT、DELETE并发执行:

以无唯一主键表为例

表结构如下:
一次mysql死锁的发现_第7张图片

单次delete事务,不提交,模拟并发提交情况(非主键删除)
image.png

另一个事务执行insert的时候,发现表锁,(无论userId是否在删除队列里)
image.png

日志如下:
一次mysql死锁的发现_第8张图片

单次delete事务,不提交(主键删除)
一次mysql死锁的发现_第9张图片

另一个事务执行insert的时候,没有发现表锁,顺利提交
image.png

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事务隔离级别下,虽然大多数插入操作是并发的,不会发生锁等待。然而,由于唯一约束的存在,这时就需要加上插入意向锁。而这也是上次死锁案例问题产生的原因。

你可能感兴趣的:(mysql)