彻底讲清 MySQL InnoDB 锁机制:从 Record 到 Next-Key 的全景理解

在真实业务中,你遇到的大多数 MySQL 性能问题、死锁问题,几乎都与"锁"有关。但很多工程师对锁的理解停留在碎片层面:

知道"行锁""间隙锁""next-key-lock",但不知道 SQL 是如何触发这些锁的、锁到底锁在哪里、为什么会锁这么多

这一篇文章,我会用工程化思维,带你一次性理解 InnoDB 锁机制的全景图

看完以后,你将具备:

✔ 能看懂锁的真实作用

✔ 能从 SQL 推断出锁范围

✔ 能解释死锁发生原因

✔ 能在面试中条理清晰地讲出锁机制


一、为什么 InnoDB 的锁机制这么复杂?

MySQL 采用 MVCC + 锁 实现事务隔离,其中最关键的隔离级别是:

  • RC:读已提交

  • RR:可重复读(默认)

RR 是企业最常见的隔离级别,它要解决"幻读"问题。

于是有了三个锁:

  • 记录锁(Record Lock)

  • 间隙锁(Gap Lock)

  • Next-Key Lock(Record + Gap)

所有复杂问题都来自这个组合。


二、InnoDB 的三种核心锁(理解它们的作用和触发条件)

Record Lock:真实行上的锁

锁的对象:一条真实存在的记录

触发场景:精确命中唯一索引

例如:

复制代码
SELECT * FROM user WHERE id = 10 FOR UPDATE;

只锁 (10] ------ 单条记录。

特点:不会锁间隙,因此不会阻止插入。


Gap Lock:只锁"间隙",不锁数据

作用:阻止"间隙内插入新数据",防止幻读。

例如:

索引中已有值:

复制代码
10 --- 20 --- 30

SQL:

复制代码
SELECT * FROM user WHERE age > 20 FOR UPDATE;

Gap Lock 会锁住:

复制代码
(20, 30)
(30, +∞)

重点:Gap Lock 不锁记录,只锁区间。


Next-Key Lock:Record + Gap 的组合锁

RR 下范围查询的默认锁模式:

复制代码
(prev_key, record_key]

例如:(假设索引有 10、20、30)

复制代码
SELECT * FROM t WHERE age BETWEEN 15 AND 25 FOR UPDATE;

锁住的区间:

复制代码
(10,20]
(20,30]

作用:

✔ 锁住命中的记录

✔ 锁住记录前的 gap → 阻止插入

这就是为什么 RR 隔离级别能规避幻读。


三、锁到底由哪些 SQL 触发?

" SQL → 锁类型" 映射表:

SQL 场景 索引情况 锁类型 原因
WHERE id = ?(唯一键) 精确命中 Record Lock 不需要锁 gap
WHERE id = ?(普通索引) 精确匹配,但非唯一 Next-Key Lock 防止幻读
WHERE age > ? / < ? 范围扫描 Next-Key Lock 必须锁 gap
BETWEEN 范围查询 范围扫描 Next-Key Lock 防止插入
无索引过滤 全表扫描 大量 Record Lock 每条记录都会被锁
LIKE '%abc' 无法走索引 表锁风险 全表扫描

一句话总结:

能精确锁住记录 → Record Lock
需要范围扫描 → Next-Key Lock
范围扫描一定会锁 gap → Gap Lock


四、锁具体加在什么区间?

假设索引中有如下值:

复制代码
10 ---- 20 ---- 30 ---- 40

来看不同 SQL 加的锁👇

WHERE id = 20 FOR UPDATE

锁:

复制代码
(10, 20]

但如果字段是主键/唯一键,会优化成:

复制代码
[20]

WHERE id > 20 FOR UPDATE

锁:

复制代码
(20,30)
(30,40)
(40,+∞)

WHERE id BETWEEN 15 AND 35 FOR UPDATE

锁:

复制代码
(10,20]
(20,30]
(30,40]

无索引条件

复制代码
SELECT * FROM user WHERE name='xxx' FOR UPDATE;

锁住所有记录:

复制代码
[10], [20], [30], [40]

→ 大量锁冲突发生的根源。


五、总结

  1. InnoDB 的锁永远基于索引。

  2. 无法精确匹配记录,就会使用 Next-Key Lock。

  3. 范围查询一定会带 gap 锁。

掌握这三点后,死锁、锁等待、幻读问题都能一眼看穿。

相关推荐
电商API_180079052473 分钟前
反向海淘是什么?现状如何?未来趋势如何?
数据库·人工智能·笔记·性能优化·数据挖掘·网络爬虫
MRSM_013 分钟前
Redis 缓存、队列、排行榜的核心用法
数据库·redis·缓存
唐青枫3 分钟前
别让 NULL 拖垮结果:MySQL COALESCE 空值兜底实战详解
sql·mysql
Trouvaille ~4 分钟前
【Redis篇】Redis 安装与启动:快速搭建一个 Redis 环境
数据库·redis·后端·ubuntu·缓存·环境搭建·安装教程
fengxin_rou10 分钟前
【Feed 高并发架构实战】:雪花 ID + 三级缓存 + 计数旁路设计详解
数据库·redis·缓存·架构·事务·并发
wand codemonkey1 小时前
SpringbootWeb【入门】+MySQL【安装】+【DataDrip安装 】+【连接MySQL】
java·mysql·mybatis
廿一夏9 小时前
MySql存储引擎与索引
数据库·sql·mysql
lzhdim11 小时前
SQL 入门 15:SQL 事务:从 ACID 到四种常见的并发问题
数据库·sql
瀚高PG实验室11 小时前
瀚高企业版V9.1.1在pg_restore还原备份文件时提示extract函数语法问题
数据库·瀚高数据库
TDengine (老段)12 小时前
TDengine Tag 设计哲学与 Schema 变更机制
大数据·数据库·物联网·时序数据库·iot·tdengine·涛思数据