孤舟笔记 并发篇十一 行锁、间隙锁、临键锁傻傻分不清?MySQL InnoDB的锁其实就这三板斧

文章目录

个人网站

面试被问到"MySQL 有哪些锁",你脱口而出"行锁、表锁"。面试官追问"间隙锁呢?临键锁呢?",你瞬间懵了。更头疼的是,这三个锁的关系像俄罗斯套娃,一个套一个,到底谁包含谁?

今天咱们就把 InnoDB 这三种行级锁彻底理清,让你面试时能画出来、讲明白。

先说结论:三种锁的核心要点

维度 说明
行锁(Record Lock) 锁定索引中的一条记录(行)
间隙锁(Gap Lock) 锁定索引记录之间的间隙,防止插入
临键锁(Next-Key Lock) 行锁 + 间隙锁,左开右闭区间
关系 临键锁 = 间隙锁 + 行锁
行锁锁定对象 索引记录,不是数据行
间隙锁目的 防止幻读,不允许往间隙里插入新记录
临键锁默认 InnoDB 默认加锁方式

一句话记住:行锁锁一条,间隙锁锁一段空隙,临键锁是它俩合体------锁一条+锁一段。

行锁:精确打击,锁住一条记录

行锁是最简单直接的一种锁------锁定索引中的某一条记录

sql 复制代码
SELECT * FROM user WHERE id = 5 FOR UPDATE;  -- 锁住 id=5 这一行 👈

别人可以读,但不能修改 id=5 这行,也不能用 FOR UPDATELOCK IN SHARE MODE 再锁它。

生活类比: 行锁就像图书馆里你正在看的那本书------别人可以透过玻璃橱窗看到(普通读),但不能拿走或涂改。

注意一个坑: 行锁锁的是索引,不是数据行。如果你的查询没走索引(比如用非索引字段更新),InnoDB 退化为表锁,所有行都被锁住!这就是为什么面试总强调"一定要走索引"。

间隙锁:锁住"空地",防止插队

间隙锁是 InnoDB 独有的,专门为了解决幻读问题。

假设你的表里 id 有 5、10、15 三条记录。间隙就是 (5, 10) 和 (10, 15) 以及 (-∞, 5) 和 (15, +∞) 这四段"空地"。

sql 复制代码
SELECT * FROM user WHERE id > 5 AND id < 10 FOR UPDATE;
-- 间隙锁锁住 (5, 10),不允许往这个区间插入新记录 👈

别人不能往 (5, 10) 之间插入 id=6、7、8、9 的记录。 但可以修改 id=5 或 id=10 本身------因为那不是间隙,那是行。

生活类比: 间隙锁就像电影院选座------你选了 5 排和 10 排,中间的空座虽然没人坐,但不允许别人再选了,防止"插队"出现新的人。

间隙锁的特殊之处: 间隙锁之间不互斥。两个事务可以同时持有同一个间隙的间隙锁------因为间隙锁只防插入,不防读取。

临键锁:行锁 + 间隙锁的合体

临键锁(Next-Key Lock)是 InnoDB 默认的加锁方式,它是行锁和间隙锁的组合:

复制代码
Next-Key Lock = Gap Lock + Record Lock

锁住的是一个左开右闭区间。比如 id 有 5、10、15,那么临键锁锁住的区间是:

  • (-∞, 5]
  • (5, 10]
  • (10, 15]
  • (15, +∞)
sql 复制代码
SELECT * FROM user WHERE id = 10 FOR UPDATE;
-- 临键锁锁住 (5, 10] 区间 👈
-- 间隙部分 (5, 10):不能插入 id=6、7、8、9
-- 行锁部分 [10]:不能修改 id=10

为什么是左开右闭? 因为 InnoDB 按 B+ 树索引顺序扫描,遇到 10 时,要把前面的间隙也锁住,防止有人在 5 和 10 之间插入新记录导致幻读。

生活类比: 临键锁就像你占了一个座位,不仅占了这个座,还把前面到上一个已占座位之间的空座都占了------别人既不能坐你的座(行锁),也不能坐中间的空座(间隙锁)。

退化规则:什么时候锁会"缩小"

临键锁不是永远锁整个区间,InnoDB 有优化机制:

  1. 等值查询,命中记录 → 临键锁退化为行锁(只锁命中行)
  2. 等值查询,未命中记录 → 临键锁退化为间隙锁(只锁间隙)
  3. 范围查询 → 保持临键锁,不会退化
sql 复制代码
-- 情况1:id=10 存在 → 退化为行锁,只锁 id=10
SELECT * FROM user WHERE id = 10 FOR UPDATE;

-- 情况2:id=7 不存在 → 退化为间隙锁,锁 (5, 10)
SELECT * FROM user WHERE id = 7 FOR UPDATE;

-- 情况3:范围查询 → 临键锁,锁 (5, 10] + (10, 15]
SELECT * FROM user WHERE id > 5 AND id <= 15 FOR UPDATE;

理解退化规则很重要,面试时能区分这三种情况,说明你真的懂了。

InnoDB 行级锁全景

复制代码
InnoDB 行级锁 全景

三种锁
├── 行锁(Record Lock)── 锁定一条索引记录
├── 间隙锁(Gap Lock)── 锁定索引间隙,防插入
└── 临键锁(Next-Key Lock)── 行锁 + 间隙锁
    └── 左开右闭区间 (a, b]

关系
临键锁 = 间隙锁 + 行锁

退化规则
├── 等值查询 + 命中 → 退化为行锁
├── 等值查询 + 未命中 → 退化为间隙锁
└── 范围查询 → 保持临键锁

口诀:行锁锁一条,间隙防插队,
      临键是合体,退化看命中。

回答技巧与点评

标准回答

InnoDB 有三种行级锁:行锁锁定索引中的一条记录;间隙锁锁定索引记录之间的间隙,防止其他事务插入新记录;临键锁是行锁和间隙锁的组合,锁定左开右闭区间。临键锁是 InnoDB 默认的加锁方式。等值查询命中记录时临键锁退化为行锁,未命中时退化为间隙锁,范围查询保持临键锁。

加分回答
  1. 设计哲学:间隙锁和临键锁是 InnoDB 在可重复读(RR)隔离级别下解决幻读问题的核心机制。MVCC 解决了普通读的幻读,而临键锁解决了当前读的幻读,两者配合实现完整的 RR 隔离
  2. 边界情况:行锁锁的是索引不是数据行,不走索引的查询会退化为表锁;间隙锁之间不互斥,但间隙锁和插入操作互斥;在读已提交(RC)隔离级别下,间隙锁基本不生效
  3. 实际应用 :在线交易系统中,用 SELECT ... FOR UPDATE 锁定账户行防止并发修改;用临键锁防止范围内新增记录导致的幻读。理解加锁范围对排查死锁至关重要
面试官点评

这道题考的是你对 InnoDB 锁机制的体系化理解。只会背三种锁的名字只能拿基础分。能说清临键锁的组成关系、退化规则、以及和幻读的关系,才能拿高分。如果你能提到不同隔离级别下锁的行为差异,面试官会认为你有实战深度。

原文阅读


内容有帮助?点赞、收藏、关注三连!评论区等你 💪

相关推荐
ElevenS_it18815 小时前
MySQL慢查询监控与告警实战:从slow_log采集到分钟级定位慢SQL的完整链路配置
android·sql·mysql
My_Java_Life15 小时前
SpringAI基于Mysql jdbc方式存储对话记忆
mysql·ai
清平乐的技术专栏15 小时前
一文读懂Kafka中的“消费”(对标MySQL数据库)
数据库·mysql·kafka
Ggsddu11122233316 小时前
制造企业MES系统推荐:2026年MES选型指南与主流系统深度评测
mysql·制造
Java成神之路-16 小时前
MySQL 参数 completion_type 深入浅出:搞懂事务提交后的“隐藏动作”
mysql
爱吃土豆的马铃薯ㅤㅤㅤㅤㅤㅤㅤㅤㅤ16 小时前
获取容器mysql管理员密码命令
数据库·mysql
文青小兵17 小时前
云计算Linux——数据库MySQL读写分离、数据库备份、恢复(十八)
linux·运维·服务器·数据库·mysql·云计算
成为你的宁宁17 小时前
【Prometheus监控Nginx/Mysql/Redis/Docker/Rabbitmq】
mysql·nginx·prometheus
rising start17 小时前
三、深入理解MySQL索引底层
数据库·mysql
UtopianCoding17 小时前
数据库语法对比详细规则
数据库·mysql·gaussdb