mysql 5.7与8.0主键范围查询加锁逻辑本质相同,均采用next-key lock,但8.0因锁可见性增强、默认rr隔离级别更严格、间隙锁范围判定更精确,导致锁信息显示更多、更全面。

MySQL 5.7 和 8.0 在主键范围查询的加锁行为上本质一致,但实际表现差异显著——不是锁规则变了,而是锁信息可见性、默认隔离级别行为、以及锁粒度细节处理方式不同。
主键范围查询的加锁逻辑本身没变,但你看到的“锁”可能根本不是同一个东西
主键上的范围查询(如 WHERE id BETWEEN 5 AND 15)在两个版本中都走主键 B+ 树,按临键锁(Next-Key Lock)原则加锁:即“行锁 + 间隙锁”的组合。但关键区别在于:
- 5.7 中
INFORMATION_SCHEMA.INNODB_LOCKS只在发生真实锁等待时才写入记录,不持锁就看不到;而 8.0 的performance_schema.data_locks是“加锁即可见”,哪怕事务还没阻塞别人,也能查到它持有哪些锁 - 5.7 默认隔离级别是
REPEATABLE-READ,但部分旧客户端或配置可能隐式降级为READ-COMMITTED,导致间隙锁被禁用;8.0 默认严格启用 RR,且innodb_locks_unsafe_for_binlog已废弃,间隙锁更稳定 - 8.0 对主键范围扫描的锁范围判定更精确,尤其在边界值不存在时(如
BETWEEN 7 AND 13,而表中只有5,10,15),它会明确锁住(5,10)和(10,15)两个间隙;5.7 有时会合并或漏报
为什么 SHOW ENGINE INNODB STATUS 在 8.0 里显示更多锁记录?
这不是因为 8.0 加了更多锁,而是因为它把“未冲突但已持有”的锁也完整上报了。5.7 的输出只聚焦于当前阻塞链,而 8.0 的 TRANSACTIONS 部分会列出每个事务持有的全部锁,包括:
- 主键索引上的
X,REC_NOT_GAP行锁(命中行) - 相邻间隙上的
X,GAP锁(防止插入) - 意向锁
IX(表级)和INSERT_INTENTION(插入意向锁,用于并发插入判断)
执行 SELECT * FROM performance_schema.data_locks WHERE LOCK_DATA LIKE '%id%' 可直接过滤主键相关锁,比翻 SHOW ENGINE 更快定位。
容易踩的坑:你以为没锁,其实锁早就在了
常见误判场景:
- 沿用 5.7 脚本查
INFORMATION_SCHEMA.INNODB_LOCK_WAITS返回空,就认为“没锁等待”,但在 8.0 这个表已不存在,必须改用performance_schema.data_lock_waits - 在 8.0 上看到大量
X,GAP锁却没对应事务阻塞,误以为是 bug——其实是正常行为:范围查询必须封锁间隙,即使当前没人在插 - 用
EXPLAIN看到走了主键索引,就默认“只锁命中的行”,忽略了间隙锁对INSERT的隐形影响;尤其在分页查询LIMIT场景下,ORDER BY id LIMIT 10,10仍会锁住跳过的所有间隙
真正要注意的不是“哪个版本锁得多”,而是你是否在用正确的工具看锁、是否理解间隙锁对并发插入的实际压制效果——这些在 8.0 里暴露得更彻底,但也更容易误读。











