游乐游手机版
首页/数据库/文章详情

MySQL当前读触发间隙锁的原因与机制解析

时间:2026-08-23 16:12
在 RR(可重复读)隔离级别下,当前读通常会触发间隙锁。这是 InnoDB 为了保证可重复读语义而强制采用的 Next-Key Lock 锁机制,它由记录锁与间隙锁共同组成,通过覆盖索引区间与索引间隙来防止幻读问题。当前读(SELECT FOR UPDATE、UPDATE、DELETE)在

在 RR(可重复读)隔离级别下,当前读通常会触发间隙锁。这是 InnoDB 为了保证可重复读语义而强制采用的 Next-Key Lock 锁机制,它由记录锁与间隙锁共同组成,通过覆盖索引区间与索引间隙来防止幻读问题。

MySQL当前读为何会触发间隙锁

当前读(SELECT ... FOR UPDATEUPDATEDELETE)在 RR 隔离级别下会触发间隙锁,这并非可选行为,而是 InnoDB 为实现 MySQL 可重复读与防止幻读而强制执行的锁策略。

RR 级别下当前读默认采用 Next-Key Lock

在 MySQL 5.7 及以上版本的 InnoDB 存储引擎中,当事务隔离级别为 REPEATABLE READ 时,当前读操作默认会应用 Next-Key Lock。这种锁机制本质上是记录锁(Record Lock)与间隙锁(Gap Lock)的组合,不是“可能会加”,而是 InnoDB 在该隔离级别下的默认并发控制方式。

  • 即使只是查询一个不存在的主键:SELECT * FROM t WHERE id = 1000 FOR UPDATE,而表中最大 id 为 999,InnoDB 仍会锁住 (999, +∞) 这一段索引间隙
  • 对于范围查询,这种表现会更明显:SELECT * FROM t WHERE age > 25 FOR UPDATE 会锁定满足条件的索引范围,以及这些索引值之间可能被插入新记录的空隙
  • 唯一索引上的 INSERT 也会涉及间隙锁:插入之前需要先申请目标区间的锁,以避免并发插入影响唯一性约束

为什么普通 SELECT 不会触发,而当前读必须加锁?

快照读(普通 SELECT)依赖 MVCC 多版本并发控制,通过读取历史版本来避免幻读;而当前读需要读取最新数据并控制后续修改边界,因此必须锁住“可能出现新记录插入”的位置。

  • 间隙锁并不直接锁定某一行数据,它锁住的是“禁止插入”的区间,也就是索引 B+ 树中相邻键值之间的空白区域
  • 如果没有间隙锁,事务 A 执行 SELECT * FROM t WHERE val BETWEEN 10 AND 20 FOR UPDATE 后,事务 B 仍然可以执行 INSERT INTO t (val) VALUES (15),那么事务 A 再次执行相同查询时就会多出一条记录,这就是典型的幻读现象
  • 严格来说,单独的间隙锁并不是完整解决幻读的手段,它属于 Next-Key Lock 的一部分;真正发挥作用的是这种组合锁对“插入意向锁(Insert Intention Lock)”的阻塞能力

哪些查询条件实际会产生间隙锁?

是否会加间隙锁,核心取决于是否发生了范围扫描、索引遍历,或者唯一性校验未命中,而不只是看 SQL 语句表面上写的是等值查询还是范围查询。

  • 主键等值查询且记录存在 → 通常只加 Record Lock,没有间隙锁部分
  • 主键等值查询但记录不存在 → 会加 Gap Lock,锁住该键值所在的索引间隙,例如 (5, 10)
  • 非唯一索引等值查询 → 即使记录存在,也可能锁住该值对应的多个可能插入位置,因为非唯一索引允许重复值,本质上仍属于间隙覆盖
  • 当前读没有走索引 → 全表扫描会退化为锁住整个索引范围,即 (−∞, +∞),实际效果非常接近表级锁

最容易被忽视的 MySQL 实战细节

间隙锁的实际边界,并不是由 SQL 中写出的数值或字符范围直接决定的,而是由底层 B+ 树索引结构决定。比如对于 WHERE name > 'Li' 这条语句,它锁住的是索引中紧邻 'Li' 的后续键值区间,而不是字典序中所有表面上大于 'Li' 的字符串范围。

另外,INSERT ... ON DUPLICATE KEY UPDATE 也不会绕开间隙锁。因为它执行前同样需要先检查唯一索引或主键约束,所以仍然会申请相应的间隙锁,在高并发场景下同样存在较高的死锁风险。

来源:https://www.php.cn/faq/3026532.html
上一篇MongoDB Atlas如何限制用户访问指定数据库权限 下一篇MySQL角色授权后仍无法使用的原因与解决方法
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
Redis是什么:核心特性、架构与应用场景解析
数据库 · 2026-09-01

Redis是什么:核心特性、架构与应用场景解析

Redis是一款基于内存的键值型NoSQL数据库,以超高读写速度和丰富的数据结构著称。本文系统梳理Redis的核心特性、架构组成、性能优势及典型应用场景,并通过与Memcached、MySQL、MongoDB的对比,帮助开发者快速判断Redis是否适合当前业务需求。

Windows 安装 MongoDB 完整图文教程
数据库 · 2026-09-01

Windows 安装 MongoDB 完整图文教程

本文详细介绍在 Windows 系统上安装 MongoDB 的完整流程。从官网下载 MSI 安装包开始,逐步演示自定义安装路径、配置 Windows 服务、跳过 MongoDB Compass 等关键选项,并提供通过系统服务列表验证安装是否成功的方法,帮助开发者快速搭建本地 MongoDB 环境。

Linux 安装 MongoDB 完整指南:依赖配置、环境变量与服务启动
数据库 · 2026-09-01

Linux 安装 MongoDB 完整指南:依赖配置、环境变量与服务启动

本文详解在 Linux 系统下安装 MongoDB 的完整流程,涵盖依赖包安装、二进制包下载解压、环境变量配置、数据与日志目录创建及服务启动验证。通过标准化命令与路径说明,帮助开发者快速完成部署并确认服务状态。

MacOS安装MongoDB完整教程
数据库 · 2026-09-01

MacOS安装MongoDB完整教程

本文介绍在MacOS系统下安装MongoDB的完整流程,涵盖下载、解压、目录配置、环境变量设置及服务启动。通过明确的命令与参数说明,帮助开发者快速完成环境搭建并验证安装结果。

Ubuntu系统安装与配置Redis完整指南
数据库 · 2026-09-01

Ubuntu系统安装与配置Redis完整指南

本文详解在Ubuntu系统中安装Redis的两种主流方式:apt在线安装与源码编译安装。涵盖版本选择逻辑、服务启停与状态检查、连接验证方法,以及在线练习工具与桌面GUI客户端的对比与使用建议,帮助开发者快速搭建并验证Redis运行环境。