undo log是逻辑反向操作指令而非备份,按lifo顺序执行回滚,受redo log保护;已提交事务无法回滚,需靠binlog+备份恢复。

Undo Log不是备份,是反向操作指令
MySQL回滚不靠“还原快照”或“覆盖磁盘旧数据”,而是靠Undo Log里存的逻辑逆操作。它不记录整行物理镜像,只记够执行反向动作的信息:比如INSERT只存主键,UPDATE只存被改字段的旧值,DELETE才存整行原始内容。回滚时,InnoDB不是读取历史数据再写一遍,而是按Undo Log逐条执行DELETE、INSERT或反向UPDATE。
回滚过程严格按LIFO顺序倒放日志
事务内每条DML语句都会生成一条Undo Log记录,并链成一个栈式结构。执行ROLLBACK时,InnoDB从栈顶开始,**逆序读取并执行**——最后做的操作最先撤销。这意味着:
- 大事务生成大量
Undo Log,回滚耗时随修改行数线性增长,不是常量时间 -
Undo Log必须在对应数据页写入Buffer Pool前就落盘(WAL原则),否则崩溃后连“撤回依据”都没了 -
Undo Log本身受Redo Log保护,防止日志自身损坏导致无法回滚
回滚生效的前提:事务必须真正在“活”着
常见“ROLLBACK没用”现象,基本都卡在这三步检查上:
-
SELECT @@in_transaction;返回0?说明当前没未提交事务 -
SELECT @@autocommit;返回1?那每条语句执行完立刻提交,ROLLBACK只能回滚空事务 -
SHOW CREATE TABLE table_name;里ENGINE=MyISAM?MyISAM根本不写Undo Log,ROLLBACK完全无效
特别注意:ALTER TABLE、CREATE INDEX这类DDL会隐式触发COMMIT,之后的ROLLBACK只对它之后的DML起作用。
已提交事务的Undo Log不会保留,也无法回滚
COMMIT一执行,对应Undo Log就进入只读归档状态,不再用于回滚。它只会留在undo表空间里,等purge线程判断无任何活跃事务需要该版本(比如MVCC快照读)后,才异步清理。所以:
- 想“撤回已提交的数据”,
ROLLBACK完全不管用 - 只能靠
binlog+ 备份做时间点恢复,或用mysqlbinlog解析row格式日志反向生成SQL -
SAVEPOINT只是事务内的标记点,不改变Undo Log生命周期,也不能绕过COMMIT的不可逆性
真正容易被忽略的是:Undo Log的物理存在和逻辑可用性是两回事——它可能还在磁盘上,但只要被purge线程标记为可回收,或者已被新事务覆盖,就再也找不回来了。











