没关系,这部分确实是 MySQL 中最抽象的概念。咱们换个方式,不用专业术语,用**“停车位”**的例子来类比,你一秒钟就能懂。
假设有一排停车位,编号分别是 1、5、10(对应数据库里 ID 为 1, 5, 10 的三行记录)。
1. Record Lock(记录锁):精准锁住“车位”
动作:你直接锁定了 5 号车位。
-
效果:别人不能停在 5 号位,也不能改 5 号位的信息。
-
范围:仅仅是 ID = 5 这一行。
-
场景:当你执行
UPDATE users SET name='xxx' WHERE id = 5;时,MySQL 就会加这个锁。
2. Gap Lock(间隙锁):锁住车位间的“空地”
动作:你锁住了 1 号到 5 号之间的空地,以及 5 号到 10 号之间的空地。
-
效果:别人不能在 1 和 5 之间插入新的车位(比如 ID=2, 3, 4)。
-
重点:它不锁 1 和 5 本身,只锁它们中间的间隙。
-
目的:防止幻读。如果你不锁间隙,别人在你查询期间插了一条 ID=3 的数据,你再次查询就会发现多了一行,像见鬼(幻觉)一样。
3. Next-Key Lock(临键锁):车位 + 左侧空地(全包)
动作:这是 InnoDB 的默认大招,它是记录锁 + 间隙锁的合体。
-
算法:它锁住的是一个左开右闭的区间。比如
(1, 5]。 -
范围:它锁住了 1 到 5 之间的空地,并且锁住了 5 号车位本身。
-
效果:
-
别人不能插入 ID=2, 3, 4(间隙锁生效)。
-
别人也不能修改或删除 ID=5(记录锁生效)。
-
但 ID=1 是不受影响的。
-
📝 为什么面试官总考这个?(核心痛点)
为了让你彻底理解,看这个操作场景:
背景:表里有 ID=1, 5, 10。
操作:事务 A 执行 SELECT * FROM users WHERE id > 5 AND id < 10 FOR UPDATE;
-
如果不加锁:事务 B 插入了 ID=7。事务 A 再次查,发现多了一个 7,这就是幻读。
-
只加记录锁:事务 A 发现 ID=5 和 ID=10 没变,但中间多出来个 7,还是防不住。
-
加了 Next-Key Lock:它会把
(5, 10]这个区间全部封死。事务 B 想INSERT INTO ... VALUES (7)?对不起,阻塞等待。
总结一下
-
Record Lock:别动我的现成数据。
-
Gap Lock:别往我两行中间插新数据。
-
Next-Key Lock:既别动我的现成数据,也别往我这插新数据(最稳,但并发性能稍微降低)。
现在这三个“锁”的形象是不是清晰多了?需要我再给你举个例子,演示一下在什么奇怪的操作下会导致“死锁”吗?(比如两个事务交叉锁间隙)