查information_schema.innodb_trx是最直接手段,通过trx_started时间戳可精准识别长事务,结合trx_state='running'和trx_query为null可判断事务空转挂起,须关联processlist确认线程真实状态。

查 information_schema.INNODB_TRX 是最直接的手段
长事务不会自动“标记自己”,但 INNODB_TRX 表里有唯一可靠的线索:trx_started。它记录事务真正开始的时间,不是连接建立时间,也不是 SQL 执行起点——而是 BEGIN 或第一条 DML 触发的那一刻。
执行这个查询就能揪出卡住几小时的事务:
SELECT trx_id, trx_mysql_thread_id AS thread_id, trx_started, TIMESTAMPDIFF(HOUR, trx_started, NOW()) AS duration_hours, trx_state, trx_query FROM information_schema.INNODB_TRX WHERE TIMESTAMPDIFF(HOUR, trx_started, NOW()) >= 1 ORDER BY trx_started ASC;
- 用
HOUR而不是SECOND,避免数字过大干扰判断;阈值设为 1 小时,比秒级更贴合“数小时”场景 -
trx_state = 'RUNNING'不代表正在跑 SQL,很可能是应用层拿了连接没提交,处于挂起状态 - 如果
trx_query是NULL,基本可断定事务已空转,只等 COMMIT/ROLLBACK - 注意别只看
duration_hours > 0,要结合业务预期——有些批处理本就该跑 2 小时,重点是“非预期的长时间空转”
必须联查 PROCESSLIST 才能确认是否真“活着”
INNODB_TRX 显示事务存在,PROCESSLIST 才告诉你这个线程现在在干啥。两者不一致是常态,尤其在连接池场景下。
运行这条语句对齐两者:
SELECT t.trx_id, t.trx_mysql_thread_id, p.ID AS processlist_id, p.USER, p.HOST, p.COMMAND, p.TIME AS processlist_time, p.STATE, p.INFO AS current_sql FROM information_schema.INNODB_TRX t JOIN information_schema.PROCESSLIST p ON t.trx_mysql_thread_id = p.ID WHERE TIMESTAMPDIFF(HOUR, t.trx_started, NOW()) >= 1;
- 重点关注
COMMAND = 'Sleep'且processlist_time > 3600的行:这是典型的“连接挂着、事务没关” - 如果
STATE是'Locked'或'Sending data',说明事务还在干活,得先看 SQL 内容再决定是否干预 - HikariCP、Druid 等连接池会让
ID复用,PROCESSLIST里看到的新查询,背后可能是老事务——所以必须靠trx_mysql_thread_id关联,不能只信ID
别依赖 SHOW ENGINE INNODB STATUS 做日常监控
这个命令输出的信息全,但它是快照式、单次性的,而且结果被截断(默认只显示最近几条事务和锁信息),不适合自动化或定时巡检。
- 它不带时间戳字段,无法直接算出运行时长;你得手动比对
TRANSACTION块里的 start time 字符串,易出错 - 输出内容格式不稳定,不同 MySQL 版本字段顺序、命名可能变化,写脚本解析风险高
- 权限要求更高:
PROCESS权限就够了,但INNODB STATUS在某些版本还需SUPER或ENCRYPTION_KEY_ADMIN - 真正该用它的场景是:刚发现一个阻塞,临时登录上去抓死锁详情或锁等待链,而不是轮询查长事务
杀连接前务必确认 trx_state 和 autocommit 状态
KILL <code>thread_id 不是万能按钮。它是否触发回滚,取决于事务当前状态和会话设置。
- 如果
trx_state = 'PREPARED'(XA 事务),KILL会导致分布式事务不一致,必须人工介入 - 如果
autocommit = OFF且trx_state = 'RUNNING',KILL会断开连接并触发隐式回滚 - 如果
trx_state = 'COMMITTING',此时KILL可能中断刷盘过程,引发 crash-safe 恢复逻辑,有小概率延长恢复时间 - 永远不要用
KILL QUERY <code>thread_id:它只停当前语句,事务还开着,反而让问题更隐蔽
真正容易被忽略的是:很多监控脚本只查时长,不验 trx_state 和连接池行为。一杀就误伤正在提交的批任务,或者放过 XA 预提交态的“幽灵事务”。











