SHOW ENGINE INNODB STATUS\G 是验证锁类型的最直接方式:在 TRANSACTIONS 部分查找 RECORD LOCKS,若末尾显示 “locks rec but not gap” 则为退化后的记录锁;若为 “locks gap before rec” 或 “locks rec but also gap”,则未退化或为间隙锁。

用 SHOW ENGINE INNODB STATUS\G 查锁类型
这是最直接、无需第三方工具的验证方式。InnoDB 会在事务活跃时把当前持有的锁信息写入状态输出,关键就看 lock_mode X locks rec but not gap 这类描述。
操作步骤:
- 开启一个事务,执行带
FOR UPDATE的唯一索引等值查询,比如SELECT * FROM user WHERE id = 10 FOR UPDATE - 保持该事务不提交,在另一个会话中执行
SHOW ENGINE INNODB STATUS\G - 在输出的
TRANSACTIONS部分查找RECORD LOCKS段落,重点看末尾是否出现locks rec but not gap
如果看到这串文字,说明加的是纯记录锁(Record Lock),即 Next-Key Lock 已退化;若出现 locks gap before rec 或 locks rec but also gap,则未退化或退化为间隙锁。
用并发插入/更新行为反向验证
Next-Key Lock 是否退化,最终体现在其他事务能否在“本该被锁住的间隙”里执行操作。退化为记录锁后,间隙是开放的。
典型验证组合:
- 前提:表
user主键id是唯一索引,现有数据为(1), (5), (10) - 会话 A 执行
SELECT * FROM user WHERE id = 5 FOR UPDATE(记录存在)→ 理论应退化为记录锁 - 会话 B 尝试
INSERT INTO user (id) VALUES (3)→ 应成功(因为 (1,5) 间隙未被锁) - 会话 B 尝试
UPDATE user SET name='x' WHERE id = 5→ 应阻塞(记录本身被 X 锁持有)
如果插入成功但更新阻塞,就是退化为记录锁的铁证。反之,若插入也被阻塞,说明加了间隙锁或完整 Next-Key Lock,退化未发生。
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
注意唯一索引和非唯一索引的差异
退化只发生在「唯一索引 + 等值查询」场景。哪怕字段逻辑上唯一,但没建唯一索引,InnoDB 就不会退化。
常见踩坑点:
-
WHERE phone = '138...'但phone字段只有普通索引(非UNIQUE),此时仍加 Next-Key Lock,不会退化 -
WHERE id = 99但表中无id=99的行 → 退化为间隙锁(如锁(5,10)),不是记录锁 - 使用
LIKE '138%'或> 100等范围条件 → 不触发退化,一律按 Next-Key Lock 处理
验证前务必确认执行计划走的是唯一索引(EXPLAIN 输出 key 列显示索引名,且 type 为 const 或 eq_ref)。
MySQL 版本与隔离级别影响不可忽略
退化行为在不同版本间有细微差别,尤其 8.0.22 之后修复了唯一索引范围查询中多余加锁的问题。而默认隔离级别必须是 REPEATABLE READ —— 在 READ COMMITTED 下,InnoDB 根本不使用 Next-Key Lock,自然也谈不上退化。
检查方式:
-
SELECT @@transaction_isolation;确保返回REPEATABLE-READ -
SELECT VERSION();确认 MySQL 版本,特别是做跨版本对比时 - 某些云数据库(如阿里云 RDS)可能打了定制补丁,行为与官方版略有出入
线上验证前,最好在同版本环境复现,避免把版本差异误判为逻辑错误。

















