长事务会持续持有行锁、间隙锁等,导致其他查询阻塞等待。其根本原因是锁在事务提交前不释放,即使只修改一行,也会使相关数据无法被其他事务读写,引发locked或waiting for table metadata lock状态。

长事务为什么会让其他查询卡住
MySQL 的行锁(比如 UPDATE 或 SELECT ... FOR UPDATE)在事务提交前不会释放,哪怕只改了一行。如果一个事务跑了 5 分钟还没 COMMIT,那它锁住的记录、间隙、甚至整个索引范围,其他想读写这些数据的语句就只能干等——表现为 Waiting for table metadata lock 或更常见的 Locked 状态。
常见错误现象:SHOW PROCESSLIST 里看到一堆 State: Locked 或 State: Waiting for table metadata lock;慢查询日志里没查到慢 SQL,但应用明显卡顿;INFORMATION_SCHEMA.INNODB_TRX 表里 TRX_STARTED 时间远早于当前时间。
- 别依赖“我只是 SELECT”,加了
FOR UPDATE或在可重复读(RR)隔离级别下执行范围查询,也会持锁 - ORM 框架(如 Django、Spring)默认开启事务,但可能没显式控制边界,一个 HTTP 请求从头包到尾就是一个长事务
-
AUTOCOMMIT=0的连接一旦忘了COMMIT,后续所有语句都在同一个未提交事务里累积锁
怎么快速发现正在拖后腿的长事务
直接查 INFORMATION_SCHEMA.INNODB_TRX 是最准的,它反映真实持有锁的事务,比 PROCESSLIST 更可靠(后者可能只显示等待者)。
常用监控 SQL:
SELECT TRX_ID, TRX_MYSQL_THREAD_ID, TRX_QUERY,
TIME_TO_SEC(TIMEDIFF(NOW(), TRX_STARTED)) AS trx_duration_sec,
TRX_STATE, TRX_ISOLATION_LEVEL
FROM INFORMATION_SCHEMA.INNODB_TRX
WHERE TIME_TO_SEC(TIMEDIFF(NOW(), TRX_STARTED)) > 60;
- 重点看
trx_duration_sec > 60,线上建议阈值设成 10–30 秒,不是等它“明显长”才干预 -
TRX_QUERY为空不等于没事——可能是事务里只执行了BEGIN,还没跑 SQL,但锁已经因之前操作持有了 - 搭配
INFORMATION_SCHEMA.INNODB_LOCK_WAITS可定位谁在等谁,但注意该表在 MySQL 8.0.1 中已被弃用,8.0+ 应用优先看performance_schema.data_lock_waits
如何从代码和配置上防住长事务
锁不是问题,不及时释放才是。核心是让事务生命周期可控、可观测、可中断。
- 应用层:所有数据库操作必须明确包裹在
BEGIN/COMMIT或等价的事务管理块中,禁止跨函数/跨 HTTP 请求延续事务上下文 - 配置层:设置
innodb_lock_wait_timeout=10(默认 50),让等待者早点失败报错Lock wait timeout exceeded,而不是无限挂起 - 连接层:对读多写少服务,考虑用
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED,减少间隙锁范围(尤其在非唯一索引上) - 监控层:用 Prometheus +
mysqld_exporter抓取mysql_global_status_innodb_row_lock_time_avg和mysql_global_status_innodb_row_lock_waits,设告警
紧急情况下怎么安全杀掉长事务
别直接 KILL 连接 ID,尤其当线程状态是 Query 或 Updating 时,可能触发回滚风暴,反而更卡。优先杀的是事务本身。
- 先确认目标:从
INNODB_TRX拿到TRX_MYSQL_THREAD_ID - 再执行:
KILL [thread_id]—— 这会中断连接,触发回滚,但比让它继续跑强 - 更稳妥方式(MySQL 5.7+):
KILL QUERY [thread_id],只终止当前语句,保留事务上下文,适合你只想打断某个慢UPDATE而不想丢整个事务的场景 - 注意:杀完立刻查
INNODB_TRX,因为回滚本身也占资源,可能持续几十秒,期间TRX_STATE是ROLLING BACK
真正难的不是杀,是判断这个事务到底在干嘛——没日志、没 trace ID、没业务上下文,你连它该不该被杀都拿不准。所以留痕比止损更重要。











