mysql innodb 意向锁_MySQL InnoDB插入意向锁

MySQL InnoDB的插入意向锁是一种插入前设置的间隙锁,用于提高并发插入性能。在INSERT操作中,先设置INSERT INTENTION LOCK,然后在新插入行上设置index record lock。在RC隔离级别下,插入意向锁主要在锁等待时出现,与GAP锁不兼容,以避免事务间的相互阻塞,提高并发性。在MySQL 8.0开始,可以通过performance_schema.data_locks查看锁信息。
摘要由CSDN通过智能技术生成

INSERT INTENTION LOCK,翻译为插入意向锁,其实准确来说应该是 INSERT INTENTION GAP LOCK,属于 GAP LOCK 子类。这个锁类型在老版本的 InnoDB 中并不存在,后来是为了优化插入性能而设计的。

在 INSERT 操作插入成功后,会在新插入的行上设置 index record lock。但,在插入行之前,INSERT 操作会首先在索引记录之间的间隙上设置 INSERT INTENTION LOCK,该锁的范围是(插入值, 向下的一个索引值)。有 shard 或 exclusive 两种模式,但,两种模式没有任何区别,二者等价。

INSERT INTENTION LOCK 在官方文档中的说明如下:

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 再加一个插入意向锁。由于插入意向锁和 Gap Lock 不兼容,因此需要等待。

INSERT INTENTION LOCK 发出按此方式进行插入的意图:多个事务向同一个 gap lock 并发进行插入时,多个事务无需相互等待。

假设已存在值为 4 和 7 的索引记录,事务 T1 和 T2 各自尝试插入索引值 5 和 6,在得到被插入行上的 index record lock 前,俩事务都首先设置 insert intention lock,于是,T1 insert intention lock (5, 7),T2 insert intention lock (6, 7),尽管这两个 insert intention lock 重叠了,但 T1 和 T2 并不互相阻塞。

如果 gap lock 或 next-key lock 与 insert intention lock 的范围重叠了,则 gap lock 或 next-key lock 会阻塞 insert intention lock。隔离级别为 RR 时正是利用此特性来解决 phantom row 问题;尽管 insert intention lock 也是一种特殊的 gap lock,但它和普通的 gap lock 不同,insert intention lock 相互不会阻塞,这极大的提高了插入时的并发性。总结如下:

1. gap lock 会阻塞 insert intention lock。事实上,gap lock 的存在只是为了阻塞 insert intention lock

2. gap lock 相互不会阻塞

3. insert intention lock 相互不会阻塞

4. insert intention lock 也不会阻塞 gap lock

INSERT 插入行之前,首先在索引记录之间的间隙上设置 insert intention lock,操作插入成功后,会在新插入的行上设置 index record lock。

MySQL 5.7 及之前,可以通过 information_schema.innodb_locks 查看事务的锁情况。但,只能看到阻塞事务的锁;如果事务并未被阻塞,则在该表中看不到该事务的锁情况。从 MySQL 8.0 开始删除了 information_schema.innodb_locks 表,添加了 performance_schema.data_locks 表,可以通过 performance_schema.data_locks 查看事务的锁情况,和 MySQL 5.7 及之前不同,performance_schema.data_locks 不但可以看到阻塞该事务的锁,还可以看到该事务所持有的锁,也就是说即使事务并未被阻塞,依然可以看到事务所持有的锁(不过,performance_schema.data_locks 并不总是能看到全部的锁)。表名的变化其实还反映了 8.0 的 performance_schema.data_locks 更为通用了,即使你使用 InnoDB 之外的存储引擎,你依然可以从 performance_schema.data_locks 看到事务的锁情况。

在 performance_schema.data_locks 表的列 LOCK_MODE 表明了锁的类型。IS或IX 表示意向锁、S,REC_NOT_GAP或X,REC_NOT_GAP 表示记录锁、S,GAP或X,GAP 表示间隙锁、S或X 表示next-key lock、S,GAP,INSERT_INTENTION或X,GAP,INSERT_INTENTION 表示插入意向锁。所以 performance_schema.data_locks 表可以更好滴帮助我们分析锁相关信息。

我们用下面三张图来说明 insert intention lock 的范围和特性。

215424d3739139b212a93347c70ba015.png

上图演示了:T1 设置了 gap lock(11, 13) (13, 18),T2 设置了 insert intention lock(16, 18),两个锁的范围重叠了,于是 T1 gap lock(13, 18) 阻塞了 T2 insert intention lock(16, 18)。同样,如果你插入 (‘d’, 12) 也同样也会与 gap lock(11, 13) 重叠。

20edeb07a17348c142dfc82be239a09d.png

上图演示了:T1 设置了 insert intention lock(13, 18)、index record lock 13;T2 设置了 gap lock(17, 18)。尽管 T1 insert intention lock(13, 18) 和 T2 gap lock(17, 18) 重叠了。但,T2 并未被阻塞。因为 insert intention lock 并不阻塞 gap lock。

786ed92a77516f5f183509c855f3e595.png

上图演示了:T1 设置了 insert intention lock(11, 18)、index record lock 11;T2 设置了 next-key lock(5, 11]、gap lock(11, 18)、PRIMARY 上的 index record lock ‘b’。此时:T1 index record lock 11 和 T2 next-key lock(5, 11] 冲突了,因此,T2被阻塞。

InnoDB 通常对插入操作无需加锁,而是通过一种“隐式锁”的方式来解决冲突。聚集索引记录中存储了事务 id。如果另外有个会话查询到了这条记录,会去判断该记录对应的事务 id 是否属于一个活跃的事务,并协助这个事务创建一个记录锁,然后将自己置于等待队列中。该设计的思路是基于大多数情况下新插入的记录不会立刻被别的线程并发修改,而创建锁的开销是比较昂贵的,涉及到全局资源的竞争。

在 RC 事务隔离级别下,虽然大多数插入操作是并发的,不会发生锁等待。然而,由于唯一约束或外键的存在,这时就需要加上插入意向锁。

如果您觉得本站对你有帮助,那么可以支付宝扫码捐助以帮助本站更好地发展,在此谢过。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值