一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

MySQL在执行Commit动作时是如何协调两阶段提交的

时间:2026-07-16 08:21:58 编辑:袖梨 来源:一聚教程网

MySQL的COMMIT是两阶段提交流程:先prepare(redo log刷盘并标记PREPARE+XID),再由binlog写入成功后触发commit(redo log更新为COMMIT),崩溃恢复时通过XID比对redo log与binlog一致性来决定提交或回滚。

MySQL 的 COMMIT 不是原子操作,而是由 InnoDB 和 Server 层协同完成的两阶段流程;你看到的“提交成功”,其实是协调者(InnoDB 事务管理模块)确认 redo logbinlog 都已按序落盘后的结果。

prepare 阶段:先让 redo log 进入可恢复状态

执行 COMMIT 后,InnoDB 立即进入 prepare 阶段:

  • redo log 写入缓冲区,并调用 fsync 刷盘(受 innodb_flush_log_at_trx_commit=1 控制),状态标记为 PREPARE,同时写入事务唯一标识 XID
  • 此时数据尚未对外可见,锁未释放,undo log 也未清理;
  • 关键点:如果此刻崩溃,InnoDB 重启后会扫描 redo log,发现 PREPARE 状态事务,但不会直接提交——它要等 binlog 的“判决”。

commit 阶段:binlog 成为最终裁决者

Server 层收到 InnoDB 的 prepare 成功反馈后,才开始写 binlog

  • binlog 追加写入文件,并调用 fsync(受 sync_binlog=1 控制),且必须关联同一 XID
  • binlog 写失败(如磁盘满、权限错误),Server 层通知 InnoDB 执行 rollback,该事务彻底作废;
  • binlog 写成功,Server 层向 InnoDB 发送 commit 指令,InnoDB 将 redo log 中对应 XID 的记录状态更新为 COMMIT(这步不强制刷盘,只需 write 到 OS page cache);
  • 随后释放锁、清理 undo log、事务真正结束。

崩溃恢复时,MySQL 怎么“读心”?

MySQL 重启时并不“猜测”,而是严格比对两个日志中的 XID

  • 如果 redo log 里有 XID 标记为 PREPARE,但 binlog 里查不到该 XID → 认定 binlog 写失败,自动回滚;
  • 如果 binlog 里有该 XID,但 redo log 中无对应 PREPARE 记录 → 理论上不应发生(因为 binlog 写入前必须过 prepare),若出现,说明流程被绕过(如禁用了 innodb_support_xa),将导致主从不一致;
  • 只有两者都存在且匹配,才完成最终提交 —— 这就是为什么 binlog 在恢复中充当“裁判”角色。

容易被忽略的配置陷阱

两阶段提交能否生效,高度依赖两个参数的实际值:

  • innodb_flush_log_at_trx_commit=0/2:prepare 阶段的 redo log 可能未刷盘,崩溃后连 PREPARE 状态都丢失,binlog 却已存在 → 主从不一致;
  • sync_binlog=0binlog 仅写入文件系统缓存,崩溃后丢失,InnoDB 会因找不到 XID 而回滚,但业务可能已收到“提交成功”响应;
  • innodb_support_xa=OFF(MySQL 5.7.7+ 默认 ON):禁用 XA 协议支持,会跳过 prepare 阶段,退化为单阶段提交,完全破坏 2PC 机制。

真正起作用的不是 COMMIT 这个语句本身,而是背后那套靠 XID 对齐、靠 fsync 顺序和靠崩溃后交叉校验维持的协作逻辑。一旦任一环节脱离这个链条,一致性就不再有保障。

热门栏目