MySQL 8.0升级后Metadata_lock等待暴增,主因是长事务未提交导致MDL锁阻塞DDL;需联合INNODB_TRX与PROCESSLIST定位Sleep但trx_state=RUNNING的悬挂事务,并结合INNODB STATUS确认是否可安全KILL。

MySQL 升级后频繁出现 Metadata_lock 等待,根本原因往往是未提交事务残留
MySQL 5.7 升级到 8.0(尤其是 8.0.29+)后,Metadata_lock 等待暴增,不是锁机制变严了,而是新版本对 DDL 操作的元数据锁等待检测更敏感、超时更短,且会显式阻塞在 Waiting for table metadata lock 状态。真正卡住它的,大概率是某个长事务没提交,哪怕只是执行了一条 SELECT 后就挂起——它仍持有表级 MDL_SHARED_READ 锁,而后续 ALTER TABLE 需要 MDL_EXCLUSIVE,直接堵死。
快速定位未提交事务:别只看 information_schema.INNODB_TRX
只查 information_schema.INNODB_TRX 可能漏掉“空闲但未提交”的连接(比如应用用完连接没 commit 就归还连接池)。必须组合三张表:
SELECT t.trx_id, t.trx_started, t.trx_state, t.trx_isolation_level, p.ID, p.USER, p.HOST, p.DB, p.COMMAND, p.TIME, p.STATE, p.INFO FROM information_schema.INNODB_TRX t JOIN information_schema.PROCESSLIST p ON t.trx_mysql_thread_id = p.ID WHERE p.COMMAND != 'Sleep' OR t.trx_state = 'RUNNING' ORDER BY t.trx_started;
-
COMMAND = 'Sleep'且trx_state = 'RUNNING'的就是典型“挂着的未提交事务”,重点盯trx_started时间 - 注意
trx_isolation_level:如果是REPEATABLE READ,事务启动后第一次 SELECT 才加一致性读视图,但 MDL 锁从BEGIN就持有了 - 如果
INFO为空但TIME > 300(秒),基本可判定是应用层异常中断或忘记 commit
KILL 前先确认影响:避免误杀活跃业务连接
不能一看到 TIME > 600 就 KILL。先检查该线程是否真在“空转”:
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
- 用
SHOW ENGINE INNODB STATUS\G查TRANSACTIONS部分,找对应trx_id,看mysql tables in use和locked tables是否为 0 —— 是则基本无实际操作,可安全终止 - 检查
PROCESSLIST中的STATE:若为Waiting for table metadata lock或Starting authentication,大概率已僵死;若为executing或sending data,需谨慎 - 优先
KILL QUERY(只中断当前语句),再观察;若仍卡住,再KILL整个连接
升级后必做的预防配置:控制长事务 + 显式超时
MySQL 8.0 默认 wait_timeout=28800(8 小时),对连接池场景太宽松。必须调整:
- 设
interactive_timeout和wait_timeout≤ 300(5 分钟),让空闲连接自动断开,避免事务悬挂 - 启用
innodb_lock_wait_timeout=30(默认 50),缩短 DDL 等待时间,失败更快暴露问题 - 关键:打开
binlog_transaction_dependency_tracking = WRITESET(8.0.22+),减少主从复制延迟引发的隐式长事务 - 应用层务必使用带超时的事务模板,例如 Spring 的
@Transactional(timeout = 30),而不是依赖数据库兜底
MDL 死锁本身不可被 SHOW PROCESSLIST 直接识别为“deadlock”,它只是单向阻塞;真正麻烦的是那些看不见的、commit 被吞掉的事务——它们不会报错,只会让下一条 ALTER 在凌晨三点突然卡住。










