D
RuntimeScope/MySQL 面试专题/locks/锁与并发控制

参考:高性能 MySQL(第 4 版) · MySQL 技术内幕:InnoDB 存储引擎(第 2 版) · MySQL 8.4 Reference Manual。每章含可暂停 Lab 动画 + 面试问答 + 书籍章节对照。

MySQL 面试 · Lab C · 锁与并发控制

锁与并发控制

主问题

-- 表里有 10、20、30;A 先执行 SELECT * FROM t WHERE id BETWEEN 10 AND 20 FOR UPDATE;

为什么另一事务 INSERT id=15 会被阻塞?

这题真正考什么

  • · 不是考你背 record / gap / next-key 这些名词。
  • · 而是考你能不能把范围锁映射到索引轴上的区间和间隙。

学完你要能做到

  • · 画出 record / gap / next-key 在索引轴上的区间
  • · 解释 insert intention 为什么等待 gap lock
  • · 说明唯一索引等值为什么通常不锁 gap
  • · 把访问路径和锁范围联系起来
30 秒答案先记结论,再看推导

A 的范围锁定读 BETWEEN 10 AND 20 在 RR 下持有(10,20] next-key lock,里面含 (10,20) 这段 gap。

INSERT 15 落在被锁间隙里,insert intention 必须等 A 释放锁,所以被阻塞。

换成唯一索引等值命中,能精确定位一条记录,就通常不锁 gap。

学习路线

点节点跳转 · 滚动时自动高亮当前位置

01

这道题到底在问什么?

表面问「INSERT 15 为什么被阻塞」,实际是在问:你能不能把范围锁映射到索引轴上的区间和间隙

10(10,20)20(20,30)30

A 锁住 [10,20] 区间(含 (10,20) 间隙)→ id=15 想插进琥珀色间隙,被挡住。

02

行锁到底锁什么?

InnoDB 的「行锁」其实锁在索引上,理解这点后面才不会卡。

锁的载体

锁在索引记录上

行锁锁的是索引记录,不是抽象的「物理行」。走哪个索引,就锁那个索引上的项。

有索引

锁精确、范围小

命中具体索引记录时,只锁到需要的那几条 / 那段区间。

无可用索引

退化为大范围锁

没有合适索引时只能扫聚簇索引,可能锁住大量记录和间隙,并发骤降。

结论「行锁锁物理行、与索引无关」是最常见误区——锁范围其实跟着访问路径走。
03

record / gap / next-key 三种锁

三个名字看着像,但锁的对象和目的完全不同。

record lock

锁已有索引记录

锁住一条已存在的索引记录,阻止它被修改或删除。命中谁就锁谁。

gap lock

锁记录间的间隙

锁住记录之间的间隙,本身不锁记录,作用是阻止往这段间隙插入新记录。

next-key lock

record + 前间隙

= record lock + 前面的 gap lock,是 RR 范围扫描防幻读的主力。

04

锁是怎么加上去的?

切换访问路径,逐步看 record / gap / next-key 落在索引轴的哪一段。

索引轴:record / gap / next-key 在 (-∞,+∞) 的具体位置

场景:普通索引范围查询 FOR UPDATE · 表中已有索引记录 10、20、30

事务 B 尚未尝试 INSERT id=15
(-∞)
边界
10
record
20
record
30
record
(+∞)
边界
record lock

锁住已经存在的索引记录(如 10、20)

gap lock

锁住两个索引值之间的空隙(如 (10,20))

⟦⟧next-key lock

一个 record + 它前面的 gap,覆盖一段半开区间

当前发生了什么

A 执行 SELECT ... WHERE id BETWEEN 10 AND 20 FOR UPDATE,这是当前读,沿主键索引扫描 [10,20] 区间。

为什么会这样

锁加在索引上,必须先确定扫描哪些记录,才能确定锁范围。

面试怎么回答

先说访问路径:唯一索引等值、普通索引范围、还是无索引扫描,决定锁范围。

常见误区

别先背锁名,锁范围是由执行计划 / 扫描路径决定的。

结论next-key lock = 命中记录的 record lock + 它前面那段 gap lock,正好挡住区间内插入。
05

访问路径决定锁范围

同一张表,访问路径不同,锁范围天差地别。

访问路径典型锁会不会锁 gap
唯一索引等值命中只锁那一条 record通常不锁 gap
普通索引范围record + next-key锁 gap,防区间插入
无可用索引扫聚簇索引,锁大量记录/间隙锁很多 gap,危险
结论锁范围跟着访问路径走——路径越精确,锁越小。所以「加合适索引」也是缩小锁范围的手段。
06

易混概念对比

五种锁一次对齐,面试里别再说串。

锁的对象RR 范围扫描会用吗
record lock已有索引记录
gap lock记录之间的间隙
next-key lock记录 + 前面的间隙会(默认)
insert intention插入位置的意向插入时
意向锁 IS/IX表级标记不直接锁行
07

面试回答生成器

按时间预算选一档念出来。

A 的范围锁定读 BETWEEN 10 AND 20 在 RR 下持有 (10,20] 的 next-key lock,里面包含 (10,20) 这段 gap。

INSERT 15 落在这段被锁的间隙里,insert intention 必须等 A 释放锁,所以被阻塞。

08

追问链 + 复习清单

勾掉每一条,这道题就算通关。

通关检查

0/5 已掌握

追问链

  • QSELECT 普通快照读会不会加 next-key lock?
  • Q死锁日志里应该重点看哪些信息?
  • Q如何通过索引设计缩小锁范围?