长事务会加剧锁竞争和回滚段压力,拖慢响应、引发阻塞死锁或oom;其行级锁长期持有、间隙锁影响范围广,undo log持续膨胀导致磁盘与性能问题。

长事务会显著加剧数据库的锁竞争和回滚段压力,直接拖慢整体响应速度,甚至引发阻塞、死锁或OOM(内存溢出)。
长事务如何放大行级锁持有时间
普通事务在执行完DML(如UPDATE/DELETE)后很快提交,对应行锁随即释放。而长事务即使只做了一次修改,只要未提交,该事务持有的行锁、间隙锁或Next-Key锁就会持续存在。
- 其他事务想修改同一行或插入满足间隙条件的数据时,会被挂起等待,形成锁等待链
- InnoDB默认等待超时为50秒(innodb_lock_wait_timeout),超时后报Deadlock或Lock wait timeout
- 若长事务还涉及范围扫描(如WHERE age BETWEEN 20 AND 30),可能长期持有多个索引区间上的间隙锁,影响面更广
长事务导致回滚段(Undo Log)持续膨胀
事务运行期间,所有被修改前的数据版本都需保留在Undo Log中,供MVCC读取和异常回滚使用。长事务不提交,这些旧版本就不能被清理。
- Undo表空间占用持续增长,可能触发磁盘空间告警,极端情况下填满ibdata1或独立undo文件
- 后台Purge线程无法回收这些“活着”的undo日志,造成历史版本堆积,拖慢SELECT查询(尤其大表COUNT或无索引扫描)
- 若此时发生崩溃恢复,重启后还需重放大量未清理的undo记录,延长启动时间
典型长事务场景与识别方法
不是执行时间长就一定是长事务,关键是“事务开启后长时间未提交”。常见诱因包括:应用端未正确关闭连接、批量处理逻辑卡在中间步骤、交互式SQL忘记COMMIT、或错误使用了SET AUTOCOMMIT=0但未手动控制。
- 查活跃长事务:SELECT * FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(TIMEDIFF(NOW(), TRX_STARTED)) > 60;
- 关联锁信息:SELECT t.*, l.LOCK_TRX_ID, l.LOCK_MODE, l.LOCK_TYPE FROM information_schema.INNODB_TRX t JOIN information_schema.INNODB_LOCKS l ON t.TRX_ID = l.LOCK_TRX_ID;
- 配合processlist看客户端IP、命令、状态:SHOW PROCESSLIST; 中State为"Sleep"但Command为"Sleep"且Time值很大,往往意味着事务空闲挂起
缓解与规避建议
核心原则是:减小事务粒度、缩短持有时间、避免在事务内做耗时操作。
- 业务层拆分大事务:比如10万条更新不要包在一个事务里,按千条一批提交
- 禁用隐式长事务:确保应用框架(如Spring)的@Transactional传播行为合理,避免REQUIRES_NEW误嵌套或超长超时配置
- 监控兜底:通过Prometheus+MySQL Exporter采集innodb_trx_trx_started、innodb_row_lock_time_avg等指标,设置>30秒事务告警
- 必要时主动KILL:对确认无用的长事务,用KILL [TRX_ID];终止(注意KILL的是connection ID,不是trx_id;可通过information_schema.PROCESSLIST查pid)










