INNODB_TRX是唯一能看清事务真实状态的入口,必须关联PROCESSLIST才能定位“Sleep但RUNNING”的悬挂事务,这类事务持锁却不执行SQL,是数据库卡顿主因。

INNODB_TRX 是唯一能看清事务真实状态的入口,仅靠 SHOW PROCESSLIST 会漏掉 90% 的持锁元凶——那些 Command = 'Sleep' 却 trx_state = 'RUNNING' 的悬挂事务。
查 INNODB_TRX 找出“假空闲”真持锁者
真正卡数据库的不是正在跑 SQL 的线程,而是开了事务却挂起不提交的连接。这类连接在 PROCESSLIST 里显示为 Sleep、INFO 为空、TIME 很大,但事务仍牢牢占着 MDL 锁或行锁。
- 必须用 JOIN 查:单看
INNODB_TRX不知道来源,单看PROCESSLIST看不到事务状态 - 执行这句:
SELECT t.trx_id, t.trx_started, t.trx_state, t.trx_isolation_level, t.trx_rows_locked, t.trx_rows_modified, p.ID, p.USER, p.HOST, p.DB, p.COMMAND, p.TIME, p.INFO FROM information_schema.INNODB_TRX t JOIN information_schema.PROCESSLIST p ON t.trx_mysql_thread_id = p.ID WHERE p.COMMAND = 'Sleep' AND t.trx_state = 'RUNNING' ORDER BY t.trx_started; - 重点关注:
TRX_STARTED比当前时间早 > 30 秒(生产建议阈值)、trx_rows_locked > 1000或trx_rows_modified > 0、trx_isolation_level = 'REPEATABLE READ'(哪怕只 SELECT 过一次也持锁) -
p.HOST和p.USER要核对清楚,避免误杀User = 'system user'(复制线程)或监控探针
确认 blocking_pid 而不是 waiting_pid
看到 Waiting for table metadata lock 或 Lock wait timeout exceeded,别急着杀报错的那个线程——它只是受害者。真正在持锁的,是 sys.schema_table_lock_waits 里的 blocking_pid,或者 INNODB_LOCK_WAITS 中的持有方。
- 优先查:
SELECT * FROM sys.schema_table_lock_waits\G—— 直接给出blocking_pid(持锁者)和waiting_pid(被卡者),sql_text字段还能看到持锁者最后执行的语句 - 如果返回为空,先确认:
SELECT @@performance_schema;必须为1;再检查采集器:SELECT * FROM performance_schema.setup_instruments WHERE NAME = 'wait/lock/metadata/sql/mdl';,确保ENABLED = 'YES' -
blocking_pid为NULL不代表没锁,很可能是隐式事务(BEGIN后只跑了一条SELECT就断开)在持锁,此时得退回INNODB_TRX + PROCESSLIST联查
KILL CONNECTION 还是 KILL TRANSACTION?
MySQL 5.7 支持 KILL TRANSACTION,但它只终止事务、保留连接;而 KILL CONNECTION(等价于老式 KILL)会断开整个连接并强制回滚。选哪个,取决于你是否想保活应用连接池。
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
- 若连接来自应用连接池(如 Java 的 HikariCP),优先用:
KILL TRANSACTION(需 MySQL 5.7+)trx_id - 若不确定版本或连接非池化,用:
KILL CONNECTION(thread_idthread_id来自INNODB_TRX.trx_mysql_thread_id,不是PROCESSLIST.ID,二者可能不同) - 严禁对
TRX_WAITING_TRX_ID IS NOT NULL的等待方执行KILL CONNECTION——这会让持锁者继续跑,堵得更死 - 执行后立刻查
SHOW PROCESSLIST,状态变成Killed是正常现象;锁是否释放,要看INNODB_TRX.TRX_OPERATION_STATE是否为rolling back,以及TRX_ROWS_MODIFIED估算剩余回滚量
KILL 后锁还在?大概率是回滚没完
执行 KILL 命令不等于锁立刻释放。InnoDB 回滚耗时通常是正向操作的 3–5 倍,尤其当 TRX_ROWS_MODIFIED 很大时,它会在后台默默滚动 undo log。
- 查状态:
SELECT trx_id, trx_operation_state, trx_rows_modified, trx_started FROM information_schema.INNODB_TRX WHERE trx_mysql_thread_id =,若thread_id;trx_operation_state = 'rolling back',就说明回滚正在进行中 - 小事务(几行更新):回滚通常 Rolling back 状态几分钟,期间锁仍被占用
- 别反复重试
KILL——刚发完命令就查INNODB_TRX可能还存在,不代表失败;要等几秒再确认 - 如果发现长时间卡在回滚且
TRX_ROWS_MODIFIED不降,可能是 I/O 压力大或 undo 表空间争用,需结合iostat和SHOW ENGINE INNODB STATUS的LOG段落进一步分析
真正难处理的不是“明显卡住”的事务,而是那种 Sleep 状态下静默持锁几十分钟的连接——它不占 CPU、不发日志、在 SHOW PROCESSLIST 里毫无威胁感,却能让后续所有 DDL 和 DML 排队等待。定位它,靠的是联查意识;杀掉它,靠的是对 trx_mysql_thread_id 和回滚机制的准确理解。










