必须先重做再回滚:重做阶段依据WAL日志将已提交但未落盘的修改追加到数据页,建立最新一致视图;回滚阶段据此识别并撤销未完成事务的脏写,确保原子性与持久性。

数据库崩溃后,恢复过程核心在于保证事务的原子性和持久性,主要依靠日志(WAL,Write-Ahead Logging)驱动两个关键阶段:重做(Redo)和回滚(Undo)。顺序不能颠倒——必须先重做,再回滚。
重做阶段(Redo Phase):确保已提交事务不丢失
重做阶段从检查点(Checkpoint)开始,扫描日志中所有在检查点之后、崩溃发生前已写入日志但尚未刷入数据页的red">已提交事务操作(INSERT/UPDATE/DELETE),按日志顺序重新应用到数据页上。
- 只处理“已写日志但未落盘”的修改,跳过已刷盘的数据页
- 重做依据是日志中的LSN(Log Sequence Number),严格按时间顺序执行,不关心事务是否完成
- 即使某事务在崩溃时处于“已提交但未写完数据页”状态,重做也能将其补全
回滚阶段(Undo Phase):清除未完成事务的脏写
重做完成后,系统识别出那些在崩溃时仍处于“活动状态”(未提交也未中止)的事务,并利用undo日志(或回滚段)将它们对数据页所做的修改全部撤销。
- 回滚操作按事务粒度进行,每个未完成事务单独处理
- 依赖undo日志中的反向操作(如INSERT对应DELETE,UPDATE对应旧值回填)
- 回滚期间可能产生新的undo日志(用于支持回滚本身的可恢复性),但这些不会被再次重做
为什么必须先重做、再回滚?
如果先回滚,可能把其他已提交事务的中间结果误删——因为崩溃时多个事务并发修改,数据页可能混杂了已提交和未提交的变更。只有先通过重做,把所有已提交的变更“追齐”到一致状态,才能准确识别哪些修改真正属于未完成事务,从而安全回滚。
- 重做建立“最新一致视图”:所有已提交变更都就位
- 回滚在此基础上清理“残留脏数据”:仅撤回未提交部分
- 顺序颠倒会导致数据丢失或逻辑错误(如丢失已提交订单)
实际恢复中的关键保障机制
现代SQL引擎(如PostgreSQL、SQL Server、Oracle)均以该模型为基础,辅以以下设计确保可靠性:
- 预写日志强制刷盘:事务提交前,其commit记录及对应redo日志必须落盘
- 检查点定期推进:减少重做范围,加快恢复速度
- undo日志持久化:保证回滚操作本身可中断恢复,避免二次崩溃导致无法回滚
- 两阶段提交(分布式场景):协调器与参与者协同,确保跨库事务的原子性










