连载中 7/22

事务与崩溃恢复:ACID 背后的 redo 和 undo

2026-05-05 · 7341 阅读 · 0 评论 · 0 赞

一次灵异扣款

聊完优化器,篇篇都是查询。老王上周遇到的事更吓人:机房闪断重启后,用户反馈「余额扣了,订单没了」。查了一圈不是 Bug——两个更新在两个事务里,扣款事务提交了,订单事务还没来得及提交就赶上断电。这个问题暴露的是团队对事务的理解停留在「begin 和 commit 之间自动全对」。ACID 不是口号,是两本日志撑出来的:redo log 和 undo log。

先厘清:ACID 各归谁管

特性靠什么实现
原子性 Atomicityundo log:做一半崩溃时,把改过的全部撤销
持久性 Durabilityredo log:提交了就不许丢,崩溃后能重放恢复
隔离性 Isolation锁 + MVCC(第 8、9 篇)
一致性 Consistency由前三者共同保证的目的,不是独立手段

redo log:先把账记下来

一个事务改了十条数据,分散在十个不同的数据页里,每个页都在 B+ 树的不同位置——直接把十个页刷盘就是十次随机写,太慢。InnoDB 的解法是 WAL(Write-Ahead Logging,先写日志):事务提交时只把「哪个页做了什么物理修改」顺序追加进 redo log(顺序写,极快),数据页先留在内存的 Buffer Pool 里慢慢刷。

崩溃了怎么办?重启后把 redo log 重放一遍,没来得及落盘的修改全部补上——顺序写的日志,换随机写的数据页,持久性就是这么买到的。redo log 是固定大小的文件组,循环写:write pos 一直往前追,checkpoint 之后的区域是待写入空间,追上 checkpoint 就得停下来先刷脏页推进 checkpoint——这也是为什么 redo 设太小的实例高峰期写入会周期性抖动。

控制「提交时日志刷多严」的参数,是事务安全和性能的三角:

innodb_flush_log_at_trx_commit = 1   # 每次提交都 fsync 落盘,最安全(默认)
# = 2 提交写到操作系统缓存,每秒 fsync:进程崩溃不丢,断电最多丢 1 秒
# = 0 每秒才写才刷:MySQL 进程崩了也可能丢 1 秒

和 binlog 的 sync_binlog 组合出来的「双 1 配置」,第 10 篇细说。

undo log:后悔药

undo log 记录的是逻辑反操作:insert 记下主键好回滚时删除,update 记下旧值好回滚时还原。它有两个职责:一是事务回滚时把数据还原;二是给 MVCC 提供旧版本——其他事务读这行时,如果看到的是历史版本,版本就顺着 undo log 的链找(伏笔,下一篇的主角)。

提交后 undo 不会立刻删,要等没有事务再需要这些历史版本时,由 purge 线程清理。由此得出一条重要的工程纪律:别开长事务——一个几小时不提交的事务,会让它之后的所有 undo 都清不掉,历史版本堆积、表空间膨胀、查询变慢,连坐全库。

崩溃恢复的完整剧本

现在能回答「断电后 MySQL 重启发生了什么」:

  • 前滚(redo):重放 redo log,把已提交、但数据页还没刷到磁盘的修改补齐。
  • 回滚(undo):找出崩溃时还提交中的事务,用 undo log 把它们改过的数据全部撤销。

一句话:redo 负责让已提交的必达,undo 负责让未提交的作废。两本日志一配合,原子性和持久性同时成立。回头看老王的灵异扣款:它不是事务失效,是两个业务动作被错误地拆成了两个事务——该在一个事务里的操作,永远放进一个事务。

redo 和 undo 的地基打好,下一楼就是隔离级别与 MVCC:不同事务同时读写一行时,各自看到的到底是什么版本?ReadView 是怎么画出来的?下一篇揭晓。

咖啡凉了,记得趁热喝。

503

10 年全栈工程师 · 503咖啡馆主理人

#MySQL#事务#redo log#undo log#ACID

评论 (0)

相关推荐

连载中 12/20

排查四件套:jstack、jmap、jstat、jcmd 的实战分工

jstack 看线程在干什么,jmap 看堆里装了什么,jstat 看运行时在变什么,jcmd 是统一入口。四把刀各管一段,配合着用没有查不动的现场。

#jstack#jmap#jstat#jcmd#排查工具
2026-09-16 · 5 阅读 · 0 评论 · 0 赞
连载中 11/20

GC 日志:把回收过程翻译成人话

一行 GC 日志里塞着七种信息:谁触发的、收了哪、停了多久、活了哪些。加上 -Xlog 配置,再加上日志分析工具,GC 不再是只能盯监控曲线的黑盒。

#GC日志#Xlog#日志分析#GC监控#Full GC排查
2026-09-16 · 13 阅读 · 0 评论 · 0 赞
连载中 10/20

ZGC:亚毫秒停顿是怎么炼成的

百 G 大堆停顿不到一毫秒,靠的是把搬家全部挪到并发阶段——着色指针让引用自带状态,读屏障让搬运中的对象依然可访问。代价是吞吐与内存,收益是停顿与堆大小解耦。

#ZGC#着色指针#读屏障#亚毫秒停顿#分代ZGC
2026-09-15 · 8 阅读 · 0 评论 · 0 赞