关键是要查INNODB_TRX中trx_query为空且trx_started远早于当前时间的记录,因其显式开启事务后未执行语句却持续持锁,需结合trx_mysql_thread_id与PROCESSLIST中Sleep线程匹配定位。

能直接抓到“开了事务但啥都不干”的空闲事务,关键不是查慢查询日志,而是盯 INNODB_TRX 里 trx_query 为空、trx_started 却远早于当前时间的记录。
查 INNODB_TRX 时为什么 trx_query 为空?
这表示事务已显式开启(比如执行了 BEGIN 或进入 @Transactional 方法),但尚未发出任何 DML/SELECT 语句。它不等于“没在运行”,恰恰相反——它正稳稳占着锁资源,只是应用层卡在了 HTTP 调用、RPC 等待、日志刷盘或异常分支里没走完逻辑。
-
trx_state = 'RUNNING'是必要条件,'LOCK WAIT'是被堵住的,不是持锁者 -
trx_started和当前时间差超过 30 秒(生产建议阈值)就该预警,别等满 10 分钟 -
trx_mysql_thread_id必须和SHOW PROCESSLIST中状态为Sleep且Time值大的线程 ID 对得上——这才是真正的“空挂”连接 - Spring 应用尤其高发:@Transactional 方法里调了 Feign 但没设
connectTimeout,或 catch 异常后忘了TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()
为什么 SHOW PROCESSLIST 看不到阻塞源头?
因为普通账号权限不足,INFORMATION_SCHEMA.INNODB_TRX 返回空结果,不代表没长事务——而是你没权限看。必须用 root 或至少具备 PROCESS + SELECT 权限的账号登录,否则连 PROCESSLIST 都只显示自己那几个连接。
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
- 只读事务、autocommit=1 的单条语句不会出现在
INNODB_TRX中,但它们不构成“空挂”问题 - 真正要揪的是那些
TRX_STARTED时间戳明显滞后于业务预期的事务(比如下单接口本该 200ms 内结束,却看到trx_started是 3 分钟前) - 宝塔面板默认 MySQL 账号通常无
PROCESS权限,需手动授权:GRANT PROCESS ON *.* TO 'your_user'@'%';
如何安全终止这类空闲事务?
MySQL 5.7+ 支持 KILL TRANSACTION,它只结束事务上下文,连接保持活跃,对连接池友好;5.6 及更早只能用 KILL QUERY,但它不释放锁,TRX_STATE 仍为 RUNNING,必须配合后续 COMMIT 或 ROLLBACK 才算真正清理。
- 先从
INNODB_TRX拿到trx_id,再执行KILL TRANSACTION 'xxx'(注意单引号) - 严禁对
User = 'system user'(主从同步线程)或定时任务账号执行 KILL,可能引发数据不一致 - KILL 后
SHOW PROCESSLIST显示Killed是正常现象,锁是否释放要看INNODB_TRX中该事务的TRX_OPERATION_STATE是否变为rolling back,以及TRX_ROWS_MODIFIED是否归零 - 别写循环脚本自动 KILL——刚查完它就提交了,KILL 就成误杀;用
pt-kill --busy-time 30 --match-command Query --victim all --kill更稳妥
空挂事务最难缠的地方在于它不报错、不慢、不进慢日志,只安静地把锁攥在手里。监控不能只盯 innodb_lock_wait_timeout 超时次数,得实时拉取 INNODB_TRX 并过滤 trx_query IS NULL AND UNIX_TIMESTAMP() - UNIX_TIMESTAMP(trx_started) > 30——这才是真正在生产里管用的信号。










