MySQL 锁机制 15 连问 · 面试速答版
一、脑图:锁全景(先记结构,再填细节)
锁层级
├─ 表锁
│ ├─ 意向锁 IS / IX
│ └─ 表锁 READ / WRITE
└─ 行锁├─ 记录锁 Record├─ 间隙锁 Gap└─ 临键锁 Next-Key
二、15 问 15 答(面试官一问一答节奏)
# | 高频问题 | 15 秒答案 |
---|---|---|
1 | 行锁 vs 表锁 | 行锁锁“行”,表锁锁“整表”;InnoDB 默认行锁,MyISAM 只有表锁。 |
2 | 何时加表锁 | ① LOCK TABLES 显式加;② ALTER/TRUNCATE 隐式加;③ UPDATE 无索引退化为全表锁。 |
3 | 怎么避免表锁 | ① 用 InnoDB;② 条件列建索引;③ 避免全表扫描;④ 分批更新。 |
4 | 乐观锁 | 用“版本号”或“CAS”替代数据库锁;MySQL 实现:UPDATE t SET val=new, ver=ver+1 WHERE id=? AND ver=? ;影响行数=1 即成功,0 则重试。 |
5 | 意向锁 | 表级“信号灯”,IS 表示要加行级共享锁,IX 表示要加行级排他锁;例:事务 A 先在 user 表加 IX,再在 id=10 行加 X。 |
6 | 共享锁 S vs 排他锁 X | S:读共享,多个事务可同时持有;X:写独占,任何其他锁互斥。 |
7 | 两阶段加锁 | 扩展阶段只加锁,收缩阶段只放锁;InnoDB RR 默认强 2PL(所有锁事务结束才放)。 |
8 | 记录锁 | 锁一行索引记录;例:SELECT * FROM t WHERE id=1 FOR UPDATE (唯一索引且命中)。 |
9 | 间隙锁 | 锁两个索引记录之间的“空隙”,防插入;例:SELECT * FROM t WHERE id=15 FOR UPDATE (id=15 不存在)。 |
10 | 临键锁 | 记录锁 + 间隙锁,左开右闭;RR 默认加;范围查询:id BETWEEN 10 AND 20 → (10,20]。 |
11 | RC 有 GAP/Next-Key? | 没有,RC 只有记录锁(除非显式 FOR UPDATE 且用到外键或唯一检查)。 |
12 | RR 如何防幻读 | MVCC(快照读)+ 临键锁(当前读)双管齐下。 |
13 | 何时加临键锁 | RR 下:① 范围查询;② 非唯一索引等值查询;③ UPDATE/DELETE 无 LIMIT。 |
14 | 唯一索引 vs 普通索引 | 唯一索引等值命中→记录锁;普通索引等值→临键锁;唯一索引插入需额外 S 锁做唯一检查。 |
15 | 死锁案例 | 线上转账批量更新账户表,顺序相反 → 交叉死锁;排查:SHOW ENGINE INNODB STATUS ;解决:统一按主键升序排序 + 批量单 SQL 更新;监控:Prometheus 死锁告警。 |
三、3 个口诀(背口诀,不背细节)
-
锁种类
“记录锁锁点,间隙锁锁缝,临键锁锁点缝”。 -
RR 防幻读
“MVCC 看旧照,临键锁堵新插”。 -
避免死锁
“顺序加锁、批量合并、索引覆盖”。
四、面试官追问彩蛋
Q:UPDATE t SET c1=1 WHERE c2=2
无索引会怎样?
A:全表扫描 → 每条记录加 X 锁 + 所有间隙加 Gap 锁 → 等价锁全表;解决:给 c2 建联合索引或改为 id IN (SELECT id ...)
。