Skip to content
困难

一句话答案

MySQL 用两阶段提交保证 redo log 和 binlog 一致:redo prepare→写 binlog→redo commit,崩溃时据此判断提交或回滚。

核心要点

为什么需要两阶段提交?

如果 redo log 和 binlog 不协调提交,会出现数据不一致:

  • 先写 redo log,宕机,binlog 没写:主库重启后数据有,但备库没同步,主从不一致
  • 先写 binlog,宕机,redo log 没写:binlog 有记录,但主库重启后数据丢失,主从不一致

两阶段提交流程(InnoDB + MySQL Server 协调):

事务提交过程:

Phase 1(Prepare 阶段):
  1. InnoDB 将 redo log 写入,状态标记为 prepare
  2. redo log 刷盘(fsync)

Phase 2(Commit 阶段):
  3. MySQL Server 将 binlog 写入并刷盘(fsync)
  4. InnoDB 将 redo log 状态从 prepare 改为 commit

崩溃恢复逻辑:
  宕机重启后扫描 redo log:
  ├─ redo log 状态为 commit → 事务已完成,无需处理
  ├─ redo log 为 prepare,且 binlog 中有对应事务记录 → 补全 commit,提交事务
  └─ redo log 为 prepare,但 binlog 中无记录 → 回滚事务

这样保证了 redo log 和 binlog 的最终一致性。

四、性能优化

追问与易错

追问方向:

  • 两阶段提交性能开销在哪?
  • 组提交是什么?
  • redo log 写满了会怎样?

易错点:

  • ❌ 混淆 MySQL 两阶段提交和分布式 2PC
  • ❌ binlog 和 redo log 可以不一致——两阶段就是保证一致

💡 记忆锚点

两阶段提交像签合同:先在草稿上签字盖章(redo prepare + 刷盘),再把正式合同寄出去(binlog 刷盘),最后在草稿上标"已生效"(redo commit)。宕机恢复时:草稿有签字且正式合同已寄出就补盖"生效"章,正式合同没寄出就撕掉草稿当没发生过。