MySQL 8.0 锁监控更透明、死锁检测更准、并发优化更细粒度:通过 performance_schema.data_locks 实时查锁,增量式 wait-for graph 提升死锁检测灵敏度,并支持动态调优与精准等待分析。

MySQL 8.0 的锁监控更透明、死锁检测更准、并发优化更细粒度;5.7 的锁行为虽一致,但你几乎看不到自己在持什么锁,排查死锁靠猜。
锁信息怎么查:INFORMATION_SCHEMA.INNODB_LOCKS 已失效
MySQL 5.7 中 INFORMATION_SCHEMA.INNODB_LOCKS 只在发生锁等待时才显示冲突双方的锁,没等上就查不到——等于你 update 了一行卡着不动,SELECT * FROM INNODB_LOCKS 返回空,根本不知道自己已经持了 X 锁。
MySQL 8.0 改用 performance_schema.data_locks,只要事务没提交,它就如实列出所有已加的锁:
- 包括表级意向锁(
IX)、行锁(X,REC_NOT_GAP)、间隙锁(X,GAP)甚至临键锁组合 - 无需构造阻塞场景,
BEGIN; UPDATE t SET col2=1 WHERE col1=5;后立刻能查到三类锁记录 - 字段
LOCK_DATA显示具体锁定的索引值(如5, 5或10, 10),直接对应到二级索引+主键回表路径
死锁检测算法:从“单次扫描”到“增量式图遍历”
5.7 和 8.0 都基于 wait-for graph 检测死锁,但实现细节影响响应速度和误报率:
- 5.7 每次检测需全量扫描所有事务的锁等待链,高并发下开销大,且可能漏掉刚形成的短周期死锁
- 8.0 引入增量式图维护:只检查新加入等待关系的边及其邻接节点,检测延迟更低,尤其在大量短事务场景下更灵敏
- 错误日志中
Deadlock found when trying to get lock附带的事务堆栈更完整,包含每个事务最后执行的 SQL(5.7 常只显示线程 ID) - 注意:两者都**不保证 100% 实时捕获**——若两个事务几乎同时释放锁再抢另一把,仍可能逃过检测
并发写入优化:间隙锁行为未变,但锁粒度控制更主动
普通二级索引等值更新(如 UPDATE t SET col2=1 WHERE col1=5)在 5.7 和 8.0 下加锁逻辑完全一致:对匹配的索引记录加 X,REC_NOT_GAP,对其后第一个不满足条件的索引项加 X,GAP(即 col1=10 行的间隙)。这不是版本差异,而是 InnoDB 行为本身。
真正区别在于你能否干预和观察:
- 8.0 支持
innodb_lock_wait_timeout动态调优,配合performance_schema.data_lock_waits可定位谁在等谁、等了多久 - 5.7 没有
data_lock_waits,只能靠SHOW ENGINE INNODB STATUS碰运气截取瞬时快照 - 8.0 的
innodb_deadlock_detect默认开启,但高并发插入场景下可临时关掉(设为 OFF),改用应用层重试——5.7 关闭后死锁将永久挂起,无 fallback
容易被忽略的兼容陷阱:SQL 语法与锁隐式交互
升级到 8.0 后某些看似无关的语法变更,会间接改变锁行为:
- 窗口函数关键字(如
RANK、FIRST_VALUE)变成保留字,若旧表字段名撞上,UPDATE ... WHERE rank = 1会报语法错误——表面是解析失败,实际是让你无法执行本该加锁的语句 - 8.0 默认字符集
utf8mb4_0900_ai_ci排序规则更强,可能导致原本走索引的WHERE name LIKE 'abc%'因 collation 不匹配退化为全表扫描+全表加锁 -
CREATE TABLE ... AS SELECT在 GTID 模式下 5.7 要求显式禁用(SET SESSION SQL_LOG_BIN=0),8.0 允许但会隐式加表级元数据锁(MDL),若并发 DDL 就容易卡住
锁机制本身没重构,但你能看见、能调、能防的维度多了——真正的瓶颈往往不在锁算法,而在你是否知道此刻哪条 SQL 正握着哪把锁、等在哪一行。











