未提交事务的数据先写入redo log并更新Buffer Pool,但对其他事务不可见;回滚时InnoDB按undo log记录还原状态,而非重放redo log;连接断开后MySQL自动回滚,期间锁不释放且可能引发高I/O。

未提交事务的数据写到哪里了
InnoDB 把未提交事务的修改先写入 redo log(物理日志),同时更新内存中的 Buffer Pool。这些变更对其他事务不可见,因为 InnoDB 通过 undo log 和多版本并发控制(MVCC)维护一致性视图。
关键点:
-
redo log是为了崩溃恢复,哪怕事务没提交也会被刷盘(取决于innodb_flush_log_at_trx_commit设置) -
Buffer Pool中的脏页是否刷回磁盘(flush),和事务是否提交无关;InnoDB 可能提前刷,也可能延迟刷 - 其他事务查不到未提交的数据,不是因为数据没写,而是因为读操作会根据
read view过滤掉未提交的版本
回滚时 undo log 怎么起作用
每个 INSERT/UPDATE/DELETE 操作都会在 undo log 中记录反向操作:INSERT 对应 DELETE,UPDATE 记录旧值,DELETE 记录原始行镜像。回滚时,InnoDB 不是“删除新数据”,而是按 undo log 中的记录还原状态。
常见误区:
- 回滚不是靠重放
redo log——redo log只用于前滚(crash recovery),不用于回滚 -
undo log存在ibdata1或独立表空间(innodb_undo_tablespaces),长期未清理的大事务会导致undo log膨胀 - 执行
ROLLBACK时,InnoDB 会逐条应用undo log记录,这个过程可能很慢(尤其大事务),且期间仍持有锁
事务中断或连接断开时,InnoDB 怎么清理
MySQL 客户端异常断连后,服务端会检测到连接关闭,并自动触发该连接上未提交事务的 ROLLBACK。这个动作由 thread_cache 线程或主连接线程完成,依赖 wait_timeout 和 interactive_timeout 控制超时时间。
注意几个实际影响:
- 如果事务持有行锁、表锁或元数据锁(MDL),回滚过程中这些锁不会立刻释放,可能阻塞其他 DDL 或长查询
- 大事务断连后回滚,可能引发磁盘 I/O 飙升、CPU 占用高,甚至导致
SHOW PROCESSLIST中长时间显示Rolling back - 设置
innodb_rollback_on_timeout=ON可让死锁或锁等待超时后自动回滚(但默认是OFF)
如何观察正在回滚的事务
直接查 INFORMATION_SCHEMA.INNODB_TRX 表,重点关注 TRX_STATE 和 TRX_STARTED 字段:
SELECT TRX_ID, TRX_STATE, TRX_STARTED, TRX_QUERY FROM INFORMATION_SCHEMA.INNODB_TRX WHERE TRX_STATE = 'ROLLING BACK';
另外,SHOW ENGINE INNODB STATUS\G 输出里的 TRANSACTIONS 部分会显示当前活跃事务及回滚进度(如 ROLLING BACK 2567890 rows),但这个计数只是估算,不一定精确。
容易忽略的细节:
- 回滚进度无法通过 SQL 实时获取精确百分比,
INNODB_TRX不暴露剩余行数 -
TRX_OPERATION_STATE字段在较新 MySQL 版本中才出现,旧版本只能靠TRX_STATE+ 日志推断 - 如果事务卡在回滚阶段,
KILL它不会立即生效——必须等回滚完成才能真正终止










