information_schema.innodb_trx 是 mysql 中唯一实时查看未提交/未回滚事务的系统表,需结合 processlist 和 performance_schema.data_lock_waits 定位阻塞源头与会话详情。

查 information_schema.INNODB_TRX 是唯一实时途径
MySQL 没有“当前事务”的全局快照命令,INFORMATION_SCHEMA.INNODB_TRX 是 InnoDB 引擎唯一能实时列出未提交/未回滚事务的系统表。它不显示已提交、已回滚、或 MyISAM 表的操作——因为那些根本不是事务。
执行:
SELECT trx_id, trx_state, trx_started, trx_mysql_thread_id, trx_query FROM information_schema.INNODB_TRX;
-
trx_state = 'RUNNING'且trx_started时间很早(比如 >60 秒),大概率是应用漏了COMMIT或ROLLBACK,不是 SQL 慢,是事务卡住了 -
trx_state = 'LOCK WAIT'表示该事务正在等锁,但表里不直接告诉你谁在持锁——别在这里死磕阻塞者 -
trx_query为NULL很常见:事务刚BEGIN、UPDATE 完正等应用发下一条、或只加了SELECT ... FOR UPDATE没后续操作,都导致字段为空 -
trx_query是VARCHAR(1024),超长会被截断;别把它当完整语句看,只是最近一次执行的片段
用 trx_mysql_thread_id 关联 PROCESSLIST 看真实会话
单看 INNODB_TRX 只知道事务状态,不知道是谁连的、从哪来的、是不是监控探针。必须用 trx_mysql_thread_id 去匹配 information_schema.PROCESSLIST 或 performance_schema.threads:
SELECT p.ID, p.USER, p.HOST, p.DB, p.COMMAND, p.TIME, p.STATE, p.INFO FROM information_schema.PROCESSLIST p JOIN information_schema.INNODB_TRX t ON p.ID = t.trx_mysql_thread_id WHERE t.trx_state = 'LOCK WAIT';
-
COMMAND = 'Sleep'且TIME很大(比如 >300),基本确定是应用拿了连接没关,事务挂着不动 -
STATE = 'Locked'或'Updating'且TIME持续上涨,说明 SQL 本身可能卡在 I/O 或锁等待,不是代码逻辑问题 -
INFO字段显示最后执行的语句,但它也可能为空——尤其用了预处理(如 PDO 设置PDO::ATTR_EMULATE_PREPARES = true)时,真实 SQL 不在这里
定位阻塞源头必须查 performance_schema.data_lock_waits
MySQL 8.0+ 中 INNODB_LOCK_WAITS 已被移除,硬套老文档会查不到数据。正确路径是:performance_schema.data_lock_waits 提供了明确的等待链:
SELECT r.OBJECT_SCHEMA, r.OBJECT_NAME, r.INDEX_NAME, r.LOCK_TYPE, r.LOCK_MODE, r.LOCK_DATA, b.PROCESSLIST_ID AS blocking_pid, b.PROCESSLIST_INFO AS blocking_sql FROM performance_schema.data_lock_waits w JOIN performance_schema.data_locks r ON w.REQUESTING_ENGINE_LOCK_ID = r.ENGINE_LOCK_ID JOIN performance_schema.data_locks b ON w.BLOCKING_ENGINE_LOCK_ID = b.ENGINE_LOCK_ID JOIN performance_schema.threads bt ON b.THREAD_ID = bt.THREAD_ID;
-
requesting_trx_id和blocking_trx_id在 8.0+ 不再是直接可关联的字段,必须通过ENGINE_LOCK_ID关联 - 锁信息是瞬态的:脚本里查完立刻存下来,再跑一遍可能就没了
- 如果查不到
blocking记录,不代表没阻塞——可能是阻塞事务已提交但锁还没释放(如大事务回滚中),或涉及外键/唯一约束的隐式锁,这时得结合SHOW ENGINE INNODB STATUS\G的LATEST DETECTED DEADLOCK块人工比对
别急着 KILL,先确认是不是真能杀
看到 trx_state = 'RUNNING' 且 trx_started 很久,第一反应不是 KILL,而是查这个线程到底在干啥:
- 先执行:
SELECT * FROM performance_schema.threads WHERE THREAD_ID = ?;
看PROCESSLIST_INFO和PROCESSLIST_DB,确认是不是订单、支付等核心库的连接 -
KILL QUERY只中断当前语句,事务仍开着;KILL才真正终止连接并触发回滚——但回滚本身可能耗时很久,尤其修改了大量行 - 很多“长事务”其实是业务必需的:比如批量导入、报表生成、跨库一致性校验。贸然 kill 可能留下中间状态,比锁表更难恢复
- 真正该盯的是那些
trx_state = 'RUNNING'+trx_query IS NULL+trx_started 的组合,这类几乎全是应用侧 bug 或异常断连残留
复杂点在于:锁等待链可能嵌套多层,data_lock_waits 只给一层直接关系;而 SHOW ENGINE INNODB STATUS\G 里的 TRANSACTIONS 段虽然杂乱,却是唯一能看到完整事务栈和锁持有全貌的地方——出问题时,它得和查询结果一起看。











