应查innodb_trx而非仅依赖show processlist,因sleep连接的time值不反映事务状态;trx_started、trx_state、trx_mysql_thread_id等字段才能真实体现事务生命周期与阻塞情况。

查 INNODB_TRX 而不是只看 SHOW PROCESSLIST
SHOW PROCESSLIST 显示的 Command = 'Sleep' 连接,哪怕 Time 值高达 1200 秒,也**完全不等于事务已结束**。它只反映连接空闲时长,而事务可能早在 5 秒前就 BEGIN 了却一直没 COMMIT 或 ROLLBACK,锁早已持住。真正能反映事务生命周期的,是 INFORMATION_SCHEMA.INNODB_TRX 视图。
关键字段必须关注:
-
TRX_STARTED:事务真实开始时间,别信PROCESSLIST.TIME -
TRX_STATE:值为'LOCK WAIT'表示已被阻塞;'RUNNING'但TRX_OPERATION_STATE卡在'starting index read'也要警惕 -
TRX_MYSQL_THREAD_ID:这是关联会话的唯一依据,和PROCESSLIST.ID不一定相等(尤其连接池复用场景) -
TRX_ROWS_LOCKED > 1000或TRX_WAITING_TRX_ID IS NOT NULL是强阻塞信号
计算真实运行时长并设合理阈值
用 TIMESTAMPDIFF(SECOND, TRX_STARTED, NOW()) 算秒数,而不是依赖 PROCESSLIST.TIME。固定“超 60 秒就杀”不靠谱——OLTP 系统里,5 秒未提交就该预警;而报表类事务跑 300 秒可能正常。
更关键的是状态优先级:
-
TRX_STATE = 'LOCK WAIT':不管才运行 0.3 秒,立刻查谁在阻塞它 -
TRX_WAIT_STARTED比TRX_STARTED更准,它是锁等待实际起点时间 - 云数据库(如阿里云 RDS)常屏蔽
PROCESSLIST全量,但INNODB_TRX一般仍可查(需CONNECTION_ADMIN权限)
定位阻塞源头:从 TRX_QUERY 到最近执行语句
INNODB_TRX.TRX_QUERY 经常为空,尤其对 Sleep 连接——它只存当前正在执行的语句,而长事务挂起后这条字段就丢了。得靠 performance_schema 拉历史。
实操步骤:
- 先从
INNODB_TRX拿到可疑的TRX_MYSQL_THREAD_ID - 查
performance_schema.threads得到对应THREAD_ID - 用该
THREAD_ID查performance_schema.events_statements_history,ORDER BY EVENT_ID DESC取最近 10 条 - 重点筛含
SELECT ... FOR UPDATE、UPDATE、DELETE的语句,再看上下文是否缺COMMIT
注意:ORM(如 Spring @Transactional)异常未捕获时,容易静默漏掉 ROLLBACK,这类事务最典型。
安全终止前必须确认三件事
直接 KILL 有风险:若事务已写入大量数据,回滚过程本身会持续占锁、消耗 IO,反而延长阻塞。动手前确认:
- 它是否还在活跃执行?查
PROCESSLIST.STATE是否为'Sending data'或'Updating',而非纯'Sleep' - 它是否真由业务逻辑驱动?比如定时任务刚启动但卡在外部 HTTP 调用,杀掉可能丢数据
- 它是否持有关键表锁?用
performance_schema.data_locks(MySQL 8.0+)或INNODB_LOCKS(5.7-)交叉验证
最易被忽略的一点:调大 innodb_lock_wait_timeout 只会让等待方等得更久,**从不解决持锁方的问题**。监控和主动干预,才是根治路径。











