MySQL next-key lock 请教

2019-08-27 18:28:10 +08:00
 silenceeeee

MySQL 版本为 5.6.42 。有如下表:

CREATE TABLE tab(
	`id` INT PRIMARY KEY AUTO_INCREMENT,
	`a` INT,
	KEY `a`(`a`)
);
INSERT INTO `tt` (`id`, `a`)
VALUES
	(1, 1),
	(2, 4),
	(3, 7),
	(4, 10),
	(5, 11);

SESSION 1:

START TRANSACTION;
SELECT * FROM tab WHERE a=7 FOR UPDATE;
SESSION 2:
INSERT INTO tab(a) VALUES(4); // blocking
INSERT INTO tab(a) VALUES(5); // blocking
INSERT INTO tab(a) VALUES(6); // blocking
INSERT INTO tab(a) VALUES(7); // blocking
INSERT INTO tab(a) VALUES(8); // blocking
INSERT INTO tab(a) VALUES(9); // blocking
INSERT INTO tab(a) VALUES(10); // success

我大概知道这里用到了 next-key lock,但是我从官方了解到的是 next-key lock 是 gap lock 加上 record lock,而 gap lock 定义的范围是索引前的间隙,在这里即 (4,7) 这个区间。

问题:为啥 INSERT INTO tab(a) VALUES(8); 这里的 8>7 在 (4,7) 区间之外也 block 了

参考 MySQL 官方文档:https://dev.mysql.com/doc/refman/5.6/en/innodb-locking.html#innodb-next-key-locks

其中有一段关于 next-key lock 的描述:

A next-key lock on an index record also affects the “ gap ” before that index record. That is, a next-key lock is an index-record lock plus a gap lock on the gap preceding the index record. 
5026 次点击
所在节点    MySQL
23 条回复
louettagfh
2021-01-19 11:11:14 +08:00
@silenceeeee 你理解的没有错 next-key lock 是 record lock 加 record 前面的 GAP lock. 但为什么你这个场景后面的 GAP 也锁住了呢?

因为表中的 `a` 字段不是二级唯一索引, 所以你执行 session 1 的时候会有 3 个锁:

1. 索引 `a` 上的 '7' 的 next-key lock.
2. 主键索引上 '3' 的 record lock.
3. 索引 `a` 上的 '10' 的 GAP lock. 即 [7, 10)

InnoDB 的加锁逻辑是遍历到下一个 record 然后添加 GAP LOCK
RedBlackTree
2021-02-02 17:26:04 +08:00
@simonlu9 你好,课程名什么呢?是丁奇的 mysql 实战吗?
RedBlackTree
2021-02-17 18:36:08 +08:00
@silenceeeee 主键的话锁住的是前一区间的 gap lock 加上 record lock ;普通索引的话除了这两个锁,还会锁住后一个区间的 gap lock 。你可以试试。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/595624

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX