InnoDB行锁本质是索引锁,无索引则退化为表锁;Record Lock锁单记录,Gap Lock锁间隙,Next-Key Lock(Record+Gap)防幻读;RR级别依赖Next-Key Lock控制幻读,但需索引支持;锁状态可通过information_schema相关视图查看。

InnoDB 的行锁不是直接锁“行”,而是通过索引实现的——没有索引,就退化为表锁。 这是理解 InnoDB 行锁机制最关键的起点。很多人遇到“明明只更新一行,却锁住整个表”的问题,根源往往就在这里。
行锁依赖索引:锁的是索引记录,不是数据行本身
InnoDB 的行级锁(Record Lock、Gap Lock、Next-Key Lock)全部作用在索引树的节点上。即使表中只有一条数据,只要 WHERE 条件无法命中索引(比如用了非索引列、函数、隐式类型转换),InnoDB 就无法精确定位记录,只能遍历聚簇索引,最终升级为表级意向锁+全表扫描,实际效果等同于锁表。
- 主键或唯一索引上的等值查询 → 加 Record Lock(单条记录)
- 普通索引上的等值查询 → 同样加 Record Lock,但会先在二级索引上加锁,再回表到聚簇索引加锁
- 范围查询(如
WHERE age > 25)→ 加 Next-Key Lock(Record Lock + Gap Lock),既锁记录也锁间隙,防止幻读 - 无可用索引 → 优化器走全表扫描,每条记录都尝试加锁,同时持有意向锁(IX),其他事务无法修改任何行,表现接近表锁
三种核心行锁类型及其触发场景
并不是所有 UPDATE/DELETE 都加同一种锁。InnoDB 根据语句类型、隔离级别、索引情况动态选择锁粒度:
- Record Lock:锁定索引中的某一条具体记录(例如主键值为 100 的行)。仅在唯一索引的等值精确匹配时最常见。
- Gap Lock:锁定两个索引记录之间的“间隙”,不包含记录本身(例如 (10, 20) 之间的空档)。主要用于 RR 隔离级别下防止插入新记录导致幻读,但 在唯一索引的等值查询中不会使用 Gap Lock。
- Next-Key Lock:Record Lock + Gap Lock 的组合,即“前开后闭”区间(如 (10, 20])。这是 RR 级别下范围查询的默认行为,也是解决幻读的核心机制。
可重复读(RR)下的幻读控制:Next-Key Lock 是关键
很多人误以为 RR 完全杜绝幻读,其实它只是通过 Next-Key Lock 把“幻象插入”也纳入锁定范围。例如执行 SELECT * FROM t WHERE id BETWEEN 10 AND 20 FOR UPDATE:
- 如果 id 是主键且存在 10、15、20 三条记录,则锁住 (−∞,10], (10,15], (15,20], (20,+∞) 四个区间
- 这意味着其他事务不能在这些间隙中 INSERT 新的 id(如 12 或 25),从而避免了再次 SELECT 时出现“多出来”的行
- 但如果 WHERE 条件没走索引,InnoDB 锁不住间隙,幻读风险依然存在
查看行锁状态:从 information_schema 入手
排查锁冲突不能只靠猜测,要结合系统视图验证:
- information_schema.INNODB_TRX:查当前活跃事务、运行时间、事务状态、SQL 语句
- information_schema.INNODB_LOCKS(MySQL 5.7 及以前)或 performance_schema.data_locks(8.0+):看每个事务持有哪些锁、锁在哪条索引记录上
- information_schema.INNODB_LOCK_WAITS:直接看到谁在等谁、等什么锁、阻塞链路
- 配合
SHOW ENGINE INNODB STATUS\G,能获取更详细的锁等待摘要和最近死锁信息










