mysql next key lock如何理解_mysql防幻读机制说明

Next-Key Lock 是 Record Lock 与 Gap Lock 的组合,仅在 REPEATABLE READ 级别启用,用于彻底防止幻读;它既锁命中行又锁左邻间隙(如 (90,102]),但等值查唯一索引时退化为纯 Record Lock。

mysql next key lock如何理解_mysql防幻读机制说明

Next-Key Lock 是什么?一句话说清

Next-Key Lock 不是某种新锁类型,而是 Record Lock(记录锁)和 Gap Lock(间隙锁)的组合体,只在 REPEATABLE READ 隔离级别下由 InnoDB 自动启用,专为堵住幻读漏洞而生。

为什么必须用 Next-Key Lock 防幻读?

幻读的本质不是“读到了别人未提交的数据”,而是“同一事务内,两次相同范围查询,第二次多出新插入的行”。MVCC 能解决脏读、不可重复读,但对 INSERT 无感知——它不修改旧行,只加新行,MVCC 的版本快照里自然看不到“未来插入”的行。

  • 仅靠 Record Lock:只能锁住已存在的行,比如 id=102,但拦不住别人插 id=101
  • 仅靠 Gap Lock:能锁住 (90, 102) 这个空隙,防止插入,但若已有 id=101,它又不锁这行本身,别人还能改它
  • Next-Key Lock 合力出手:既锁住命中行(如 id=102),又锁住它左边的间隙(如 (90, 102]),真正封死“该范围内增删改”的所有可能

Next-Key Lock 怎么加?关键规则和常见退化场景

加锁不是全表扫描式暴力覆盖,而是严格按索引查找路径走,只锁“访问到的索引项”及其对应区间。默认单位是左开右闭区间,比如 (5, 10] 表示:不锁 5,但锁 105~10 之间的所有空隙。

神卷标书

神卷标书

神卷标书,专注于AI智能标书制作、管理与咨询服务,提供高效、专业的招投标解决方案。支持一站式标书生成、模板下载,助力企业轻松投标,提升中标率。

下载

  • 等值查询 + 唯一索引(如主键):直接退化为 Record Lock

    SELECT * FROM users WHERE id = 15 FOR UPDATE;

    → 只锁 id=15 这一行,不锁任何间隙

  • 等值查询 + 普通索引,且记录不存在:退化为 Gap Lock

    SELECT * FROM users WHERE age = 12 FOR UPDATE;

    → 若当前最大 age 是 10,则锁 (10, +∞),阻止插入 age > 10 的新记录

  • 范围查询(如 BETWEEN、>、:典型 Next-Key 场景。
    SELECT * FROM users WHERE age BETWEEN 20 AND 30 FOR UPDATE;

    → 锁所有满足条件的行 + 它们左侧间隙,实际可能覆盖 (18, 20], (20, 25], (25, 30], (30, 35] 等多个区间

  • 无索引字段查询:InnoDB 会退化为全表扫描,对每条聚簇索引记录都加 Next-Key Lock,相当于整张表被锁住,极易阻塞

实战中容易踩的坑

Next-Key Lock 是隐形的,你没写 FOR UPDATELOCK IN SHARE MODE 就不会触发;但一旦用了,它的影响远超直觉。

  • 看似查 WHERE age = 25,但如果 age 是普通索引,且表里有 age=24age=26,那它实际锁的是 (24, 26],别人插 age=25.5(如果字段允许)也会被卡住
  • SELECT ... FOR UPDATE 在 RR 级别下一定走 Next-Key,但 UPDATE ... WHERE 却只锁命中的行(Record Lock),除非 WHERE 是范围条件
  • 间隙锁本身不冲突(多个事务可同时持有同一间隙锁),但只要有人试图在该间隙 INSERT,就会被全部阻塞——这是排查“莫名插入卡住”的第一怀疑点
  • 降低隔离级别到 READ COMMITTED 会彻底禁用 Gap Lock 和 Next-Key Lock,幻读重现,但并发写入阻塞减少;这不是修复,是绕过

真正要稳住幻读,得从设计上确保查询条件能命中唯一索引,或用业务层加分布式锁兜底;指望数据库自动锁全量范围,往往锁得比需要的宽得多。

https://www.php.cn/faq/1963921.html

发表回复

Your email address will not be published. Required fields are marked *