mysql 8.0中定位持有mdl锁的线程需启用performance_schema及data_locks等consumers,再通过innodb_trx与data_lock_waits关联查询,重点识别trx_state为running但processlist_state为sleep且time超60秒的静默长事务,因其常因autocommit=0下未提交的select而持续持有mdl_shared_read锁。

查清谁在 hold MDL 锁,而不是等超时
MySQL 8.0 中 Waiting for table metadata lock 不会报错,只会卡住。靠等 lock_wait_timeout 超时(默认一年)毫无意义,必须立刻定位持有锁的线程。
关键查询依赖 performance_schema.data_lock_waits,但该表默认启用≠数据可查——需确认两件事:
-
performance_schema全局开关为ON(查global_variables表) - 相关 consumer 已激活:
data_locks、events_statements_current的值必须是YES(查setup_consumers)
满足后执行:
SELECT r.trx_id waiting_trx_id, r.trx_mysql_thread_id waiting_thread, r.trx_query waiting_query,
b.trx_id blocking_trx_id, b.trx_mysql_thread_id blocking_thread, b.trx_query blocking_query
FROM performance_schema.data_lock_waits w
INNER JOIN information_schema.INNODB_TRX b ON b.trx_id = w.BLOCKING_TRX_ID
INNER JOIN information_schema.INNODB_TRX r ON r.trx_id = w.REQUESTING_TRX_ID;
结果中 blocking_query 往往是 SELECT ... 或空(休眠事务),重点看 blocking_thread 和其 PROCESSLIST_TIME ——超过 60 秒的休眠连接大概率是罪魁祸首。
识别长事务:不只是 SELECT,还有隐式 BEGIN
很多人以为只有显式 BEGIN + SELECT 才会长期持锁,其实更常见的是自动提交关闭(autocommit=0)后的一条 SELECT 就足以锁住整张表。
典型误操作场景:
- 应用连接池配置错误,未重置
autocommit - DBA 在客户端执行
SET autocommit=0后忘记恢复,再执行一条SELECT就进入“静默长事务”状态 - 监控脚本或定时任务用
START TRANSACTION查询后未COMMIT或ROLLBACK
查这类事务不能只看 INNODB_TRX 的 trx_state='RUNNING',更要关注 trx_started 时间戳和 trx_mysql_thread_id 对应的 PROCESSLIST 状态——Sleep 且 Time 值很大,就是它。
ALTER TABLE 卡住时,为什么后续 SELECT 也卡?
这不是 MySQL 故障,而是 MDL 锁升级链导致的必然现象:
- 事务 A 持有
MDL_SHARED_READ(来自SELECT) - 事务 B 执行
ALTER TABLE,需要MDL_EXCLUSIVE→ 被 A 阻塞,进入等待队列 - 事务 C 执行新
SELECT,需要MDL_SHARED_READ→ 但 MySQL 8.0 的锁队列是 FIFO,C 必须等 B 获取到锁并执行完才能轮到自己
所以你看到的不是“B 卡住”,而是“B 把整条队列堵死了”。此时杀掉 B 并不能立即释放 C,必须先杀 A(释放读锁),B 才能继续,C 才能进队。
这也是为什么不能盲目 KILL 等待中的 DDL 线程——它不持有锁,只是排队;真正要动的是前面那个沉默的读事务。
生产环境应急与长期规避要点
应急处理优先级:先查 blocking_thread → 再确认是否可 kill(比如非核心监控线程)→ 若不可杀,考虑临时调低 lock_wait_timeout 防雪崩(如设为 5 秒)。
长期规避的关键点容易被忽略:
- 所有应用连接初始化时强制
SET autocommit=1,禁止服务端默认关闭自动提交 - DBA 操作一律使用带超时的客户端(如
mysql --connect-timeout=10 --execution-timeout=30) - 禁止在业务高峰期执行 DDL,哪怕加了
ALGORITHM=INPLACE—— 它仍需短暂 X 锁,而短锁在高并发下也极易排队
最隐蔽的风险点:MySQL 8.0 的 MDL 锁兼容性比 5.7 更严格,不是“更松”,而是“更一致”。别指望它绕过长事务,它就是要让你看清谁在挡路。











