INFORMATION_SCHEMA.INNODB_TRX 是唯一实时查看未提交/未回滚事务的入口,可查trx_state、trx_started、trx_query等字段定位长事务与锁等待,但需关联PROCESSLIST和performance_schema.data_lock_waits综合分析。

INFORMATION_SCHEMA.INNODB_TRX 是唯一能实时看到未提交/未回滚事务的入口,其他方式(如 SHOW PROCESSLIST、performance_schema.threads)只反映连接或语句状态,不等价于“事务正在运行”。
直接查 INNODB_TRX 能看到什么
执行 SELECT * FROM information_schema.INNODB_TRX\G 后,重点关注这几列:
-
trx_state:值为RUNNING表示事务在执行中;LOCK WAIT表示正卡在等锁;COMMITTING或ROLLING BACK是瞬态,一般看不到 -
trx_started:时间戳。如果超过 60 秒还没结束,大概率是应用漏了COMMIT或ROLLBACK,不是 SQL 慢,是事务挂住了 -
trx_query:最近一次执行的语句片段,VARCHAR(1024),超长会被截断;值为NULL很常见——比如刚BEGIN、只做了SELECT ... FOR UPDATE没后续操作、或用预处理没绑定参数 -
trx_mysql_thread_id:必须拿它去关联PROCESSLIST,否则不知道这个事务是谁连的、从哪来的、是不是健康心跳
为什么不能只看 trx_query 就判断问题
trx_query 不是完整事务上下文,也不能代表阻塞源头。常见误判点:
- 值为空时,别急着认为“没在干活”——可能刚加完行锁,正等应用发下一条语句
- 值显示
UPDATE t SET x=1 WHERE id=100,但实际阻塞者可能是另一条没出现在这里的DELETE,因为锁是按行/间隙持有的,不是按语句绑定的 - 用了
PDO::ATTR_EMULATE_PREPARES = true时,trx_query和PROCESSLIST.INFO都为空,真实 SQL 压根不落表 - MyISAM 表上的操作不会出现在
INNODB_TRX里——它只管 InnoDB 事务
MySQL 8.0+ 必须搭配 data_lock_waits 才能定位谁在持锁
INNODB_TRX 显示 trx_state = 'LOCK WAIT',但表里不告诉你谁在持锁。老文档里提的 INNODB_LOCK_WAITS 在 MySQL 8.0 已被移除,硬查会返回空。
正确做法是用 performance_schema.data_lock_waits 查等待链:
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 JOIN information_schema.INNODB_TRX r ON w.BLOCKING_TRX_ID = r.trx_id JOIN information_schema.INNODB_TRX b ON w.REQUESTING_TRX_ID = b.trx_id;
- 注意字段名大小写:
BLOCKING_TRX_ID和REQUESTING_TRX_ID是大写的,拼错查不到结果 - 该查询需开启
performance_schema且相关 instrument(默认通常已开),否则data_lock_waits为空 - 如果
data_lock_waits没数据但确实有锁等待,检查是否启用了lock_wait_timeout或事务被自动回滚了
结合 PROCESSLIST 看真实会话行为
单靠 INNODB_TRX 无法区分是业务逻辑卡住,还是连接泄漏。必须用 trx_mysql_thread_id 关联 information_schema.PROCESSLIST:
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 = 'RUNNING' AND t.trx_started < NOW() - INTERVAL 60 SECOND;
-
COMMAND = 'Sleep'且TIME > 300:基本确认是应用拿了连接没释放,事务挂着不动 -
STATE = 'Updating'或'Sending data'且TIME持续上涨:SQL 本身可能卡在磁盘 I/O、网络传输或锁等待,不是代码没提交 -
INFO为空但COMMAND = 'Query':说明语句已发、正在执行中,还没返回结果——此时trx_query可能也为空,别误判为“没在跑”
真正容易被忽略的是:事务生命周期和连接生命周期不是一回事。一个连接可以 BEGIN 多次,也可以在 COMMIT 后继续复用;而 INNODB_TRX 只反映当前活跃事务,不是连接状态。查的时候,永远带着“这个事务属于哪个应用线程、它到底想干什么”的疑问去交叉验证。


















