应查INFORMATION_SCHEMA.INNODB_TRX:TRX_STATE='RUNNING'且TRX_QUERY IS NULL、TIMESTAMPDIFF(SECOND, TRX_STARTED, NOW())>30秒、TRX_ROWS_MODIFIED>0但无变化,才确认事务真卡住而非正常执行。

怎么确认一个事务真卡住了,而不是在正常执行?
只看 SHOW PROCESSLIST 容易误判:State 是 Query 但 Info 为空、或 State 是 Sleep 且 Time 很大,都不等于事务已“死”。关键得查 INFORMATION_SCHEMA.INNODB_TRX:
-
TRX_STATE = 'RUNNING'且TRX_QUERY IS NULL:事务没在跑 SQL,大概率空转挂起 -
TIMESTAMPDIFF(SECOND, TRX_STARTED, NOW()) > 30:生产建议阈值设为 30 秒,不是 5 分钟——早干预比等锁爆好 -
TRX_ROWS_MODIFIED > 0但长时间无变化:说明它改了数据却卡在应用层没提交,不是只读事务
别忽略 TRX_ISOLATION_LEVEL 和 TRX_MYSQL_THREAD_ID 关联 PROCESSLIST 查 Host/User,排除监控脚本或 DBA 工具的连接。
kill 的目标必须是线程 ID,不是事务 ID
INNODB_TRX.TRX_ID 是 InnoDB 内部编号,KILL 命令根本不认它。真正要杀的是 TRX_MYSQL_THREAD_ID 字段值:
- 执行
KILL 45(假设查到线程 ID 是 45)会断开连接,并触发隐式回滚 - MySQL 5.7+ 支持
KILL TRANSACTION 45,它只终止事务、保持连接存活,适合用连接池的业务 -
KILL QUERY 45不结束事务,TRX_STATE仍为RUNNING,锁不会释放,慎用
注意:重复执行 KILL 可能报 Unknown thread id,不代表第一次失败,只是线程已被回收。
kill 后锁还在?不是命令没生效,是回滚没做完
KILL 发出后,SHOW PROCESSLIST 显示 State = 'Killed' 是正常中间态。InnoDB 必须按 undo log 逆向回滚,耗时通常是正向操作的 3~5 倍:
- 小事务(修改几十行):一般 100ms 内完成
- 大事务(百万行 UPDATE):可能卡在
Rolling back状态几分钟 - 查
INNODB_TRX.TRX_OPERATION_STATE确认是否真在回滚,再看TRX_ROWS_MODIFIED估算剩余工作量
别只盯着 PROCESSLIST 里有没有那个 ID——线程 ID 可能被复用,而事务残留会导致后续 ALTER TABLE 或 TRUNCATE 持续阻塞。
为什么不能写脚本批量 kill 所有超时事务?
- 并发下刚查完就提交了,脚本却把刚结束的事务又
KILL 一遍
- 若拼接用户输入生成 SQL,有注入风险(比如
TRX_USER 字段含恶意内容)
-
KILL 后不验证 INNODB_TRX 是否清空,下次轮询又重复执行
KILL 一遍 TRX_USER 字段含恶意内容) KILL 后不验证 INNODB_TRX 是否清空,下次轮询又重复执行 更稳妥的是用 pt-kill --busy-time 30 --match-command Query --victim all --kill:它内置竞争规避、连接重试、日志审计,还能加 --print 先预演。人工干预前,务必先查 performance_schema.threads 留痕——谁连的、执行过什么、是不是报表导出类合理长事务。
最易被忽略的一点:kill 后必须立刻查 INNODB_TRX 是否为空,而不是只看连接是否消失。


















