一眼识别“假运行”事务:查innodb_trx中trx_state='running'且(trx_query is null or trx_query='')、trx_started超60秒的记录,再关联processlist——若command='sleep'且time>300、state为空或为'locked'、或p.id为null,即为悬挂事务。

怎么一眼看出哪个线程在“假运行”
事务状态显示 trx_state = 'RUNNING' 并不等于真在执行——它可能卡在锁等待、磁盘写入失败、网络断开后未清理,甚至只是空转。真正可疑的是那些 trx_query IS NULL 或 trx_query = '',但 trx_started 已经超过业务合理耗时(比如 >60 秒)的记录。
直接查 INFORMATION_SCHEMA.INNODB_TRX 只能看到事务视角;必须和 PROCESSLIST 关联,才能确认这个“RUNNING”背后是不是一个已断连却没释放资源的僵尸连接。
推荐这条关联查询:
SELECT t.trx_id, t.trx_state, t.trx_started, t.trx_mysql_thread_id, p.COMMAND, p.TIME, p.STATE, t.trx_query FROM INFORMATION_SCHEMA.INNODB_TRX t LEFT JOIN INFORMATION_SCHEMA.PROCESSLIST p ON t.trx_mysql_thread_id = p.ID WHERE t.trx_state = 'RUNNING' AND (t.trx_query IS NULL OR t.trx_query = '') AND TIME_TO_SEC(TIMEDIFF(NOW(), t.trx_started)) > 60 ORDER BY t.trx_started;
-
COMMAND = 'Sleep'且TIME > 300:基本可判定客户端已断,但事务还挂着 -
STATE显示'Locked'或为空:说明线程处于非活跃等待态,不是正在跑 SQL - 如果
p.ID查不到对应行(NULL):线程已消失,但事务未回滚 → 典型悬挂
为什么只查 PROCESSLIST 不够用
SHOW PROCESSLIST 看到的只是连接层快照,它会漏掉三类关键情况:
- 事务已启动但还没执行第一条语句(
trx_query为空),此时COMMAND可能还是'Sleep',但锁已经加了 - 客户端异常断连后,连接被回收,
PROCESSLIST里没了,但INNODB_TRX还留着事务(尤其在大事务回滚慢时) - 某些 ORM(如 Django 的
@transaction.atomic)在异常未捕获时会静默维持事务上下文,PROCESSLIST里只显示'Sleep',毫无提示
换句话说:PROCESSLIST 告诉你“谁在线”,INNODB_TRX 告诉你“谁占着锁”。两者必须一起看,否则你会误判——比如把一个刚启动、还没来得及执行 SQL 的合法事务当成僵尸杀掉。
trx_mysql_thread_id 和 KILL 命令怎么配对才安全
trx_mysql_thread_id 是你在 KILL 命令中唯一该用的 ID,千万别用 trx_id(那是 InnoDB 内部事务号,KILL 不认)。
执行前务必再核对一次该线程当前状态:
SELECT ID, COMMAND, TIME, STATE FROM INFORMATION_SCHEMA.PROCESSLIST WHERE ID = <code>12345</code>;
- 如果返回空行:连接已断,
KILL <code>12345仍会触发服务端回滚(MySQL 5.7+ 支持) - 如果
COMMAND = 'Query'且STATE是'Sending data'或'Updating':别急着 kill,它可能真在干活 - 如果
TIME持续增长但STATE长期卡在'Waiting for table metadata lock'或'Locked':大概率是被 DDL 或长事务阻塞,要先查INNODB_LOCK_WAITS
注意:KILL <code>12345 终止的是连接,会强制回滚整个事务;KILL QUERY <code>12345 只中断当前语句,事务仍保持打开——对悬挂事务无效。
磁盘满、锁等待、网络断这三类原因怎么快速区分
同一现象(trx_state = 'RUNNING' + trx_query IS NULL),不同根因处理方式完全不同:
-
磁盘空间不足:先跑
df -h /var/lib/mysql和df -h $(dirname $(my_print_defaults --defaults-file=/etc/my.cnf | grep ibtmp1 | awk '{print $2}'));再查错误日志是否有OS error code 28或Cannot create temporary file -
锁等待卡死:查
INNODB_LOCK_WAITS,看有没有BLOCKING_TRX_ID对应的事务;若有,重点盯那个 blocking 事务的trx_started时间 -
网络中断残留:
PROCESSLIST里找不到对应线程,但INNODB_TRX里还有;且trx_operation_state(需 MySQL 8.0+)长期为'fetching rows'或'starting index read'却无进展
最易被忽略的一点:这三个原因可能同时存在。比如磁盘快满时触发大量临时表写入失败,导致事务卡在 Waiting for query execution,此时它既像锁等待,又像网络断连——必须靠错误日志和磁盘检查交叉验证,不能只信 TRX 表字段。











