Canvas粒子系统打造烟花模拟器:从物理模型到性能优化全解析
2026/9/26 23:48:56
从 S 锁 / X 锁 到 Next-Key Lock:MySQL InnoDB 锁机制硬核拆解
MySQL 的 InnoDB 引擎锁机制是面试和生产中高频考点,尤其是幻读如何被解决、Next-Key Lock到底锁了什么、加锁规则如何判断等。下面从基础到进阶,一层层拆解。
InnoDB 锁主要分三层:
重点关注行级锁的三种形态 + 两种模式:
| 锁类型 | 英文名 | 模式(Mode) | 作用 | 是否允许其他事务读写 |
|---|---|---|---|---|
| 共享锁 | Shared Lock | S | 允许读,不允许写 | 其他事务可加 S,不允许加 X |
| 排他锁 | Exclusive Lock | X | 允许读 + 写,不允许其他事务读写 | 其他事务都阻塞 |
S/X 是锁的“权限”,而 Record/Gap/Next-Key 是锁的范围。
| 锁名称 | 英文名 | 锁住范围 | 典型场景 | 是否防幻读 |
|---|---|---|---|---|
| 记录锁 | Record Lock | 仅仅锁住一条索引记录本身 | 唯一索引 + 等值查询(主键/唯一索引) | × |
| 间隙锁 | Gap Lock | 锁住索引记录之间的间隙(不含记录本身) | 防止在间隙中插入新记录 | √(部分) |
| 临键锁 | Next-Key Lock | 记录 + 它前面的间隙(左开右闭) | InnoDB RR 隔离级别下默认加的锁 | √(最强) |
关键记忆:
幻读定义(ANSI SQL 标准):
同一事务内,前后两次范围查询,结果集行数不同(主要是插入导致)。
快照读(普通 SELECT)靠 MVCC 解决不可重复读,但无法防插入→ 因此防不了幻读。
当前读(SELECT … FOR UPDATE / LOCK IN SHARE MODE / UPDATE / DELETE)会加锁。
InnoDB 在Repeatable Read(默认隔离级别)下,通过Next-Key Lock实现当前读防幻读。
核心规则(InnoDB RR 级别下):
经典例子(假设表 t 有字段 id 主键,c 非唯一索引)
CREATETABLEt(idINTPRIMARYKEY,cINT,KEYidx_c(c));INSERTINTOtVALUES(5,10),(10,20),(15,30);事务 A:
BEGIN;SELECT*FROMtWHEREc=15FORUPDATE;加锁分析:
事务 B能做什么?
| 操作类型 | 隔离级别 | 索引情况 | 加锁类型(默认) | 防幻读? |
|---|---|---|---|---|
| SELECT … FOR UPDATE | RR | 非唯一索引 + 范围 | Next-Key Lock | 是 |
| SELECT … FOR UPDATE | RR | 唯一索引 + 等值命中 | Record Lock | 否(但当前读安全) |
| UPDATE / DELETE | RR | 非唯一索引 | Next-Key Lock | 是 |
| INSERT | - | - | 插入意向锁(不互斥插入) | - |
| SELECT … (快照读) | RR / RC | - | 无锁(MVCC) | 否 |
| RC 隔离级别 | RC | - | 仅 Record Lock | 否 |
一句话总结:
InnoDB 通过S/X 控制读写权限,用Record Lock 锁行,用Gap Lock 锁间隙,最终用Next-Key Lock(Record + 前间隙)在RR 隔离级别下实现了当前读防幻读,这是 MySQL 与传统数据库在隔离级别实现上的最大区别之一。
想看具体死锁案例、锁等待分析(information_schema)、还是间隙锁导致的性能问题优化?可以继续深挖~