Skip to content
进阶

一句话答案

2PC 两阶段提交(prepare→commit),问题:协调者单点+参与者阻塞;3PC 增加 canCommit 预检+超时机制减少阻塞。

核心要点

2PC(Two-Phase Commit)两阶段提交:

引入一个协调者(Coordinator)来统一调度多个参与者(Participant)的事务提交。

阶段一:Prepare(准备阶段 / 投票阶段)

  协调者 ──────→ 参与者1:「能否提交事务?」
           ──────→ 参与者2:「能否提交事务?」
           ──────→ 参与者3:「能否提交事务?」

  各参与者执行事务操作(但不提交):
    ① 执行 SQL
    ② 写 redo log(重做日志)和 undo log(回滚日志)
    ③ 锁定相关资源

  参与者 ──────→ 协调者:返回 YES(可以提交)或 NO(无法提交)


阶段二:Commit / Rollback(提交 / 回滚阶段)

  情况A:所有参与者都返回 YES
    协调者 ──────→ 所有参与者:发送 Commit 请求
    参与者:提交事务,释放资源 → 返回 ACK
    协调者:收到所有 ACK → 事务完成

  情况B:任一参与者返回 NO 或超时未响应
    协调者 ──────→ 所有参与者:发送 Rollback 请求
    参与者:利用 undo log 回滚事务,释放资源 → 返回 ACK
    协调者:收到所有 ACK → 事务回滚完成

2PC 的四大问题:

问题说明
同步阻塞阶段一执行完后,所有参与者锁定资源等待协调者指令,期间资源被阻塞
单点故障协调者挂了,参与者一直等待,资源无法释放,整个事务阻塞
脑裂/数据不一致阶段二协调者发 Commit 后挂了,部分参与者收到 Commit 提交了,部分没收到未提交
过于保守任一参与者失败或超时都会回滚整个事务,没有容错机制

3PC(Three-Phase Commit)三阶段提交:

在 2PC 的基础上做了两个改进:(1) 引入超时机制;(2) 增加 CanCommit 预询问阶段。

阶段一:CanCommit(预询问阶段)
  协调者 → 参与者:「你能执行这个事务吗?」(不执行,仅检查条件)
  参与者 → 协调者:YES / NO
  → 如果有人 NO 或超时 → 直接终止,不会锁定任何资源

阶段二:PreCommit(预提交阶段)
  协调者 → 参与者:「请执行事务,但先别提交」
  参与者:执行事务、写 redo/undo log、锁定资源
  参与者 → 协调者:ACK
  → 如果有人 NO 或超时 → 协调者发 Abort → 参与者回滚

阶段三:DoCommit(正式提交阶段)
  协调者 → 参与者:「正式提交」
  参与者:提交事务、释放资源
  参与者 → 协调者:ACK

  【关键改进】如果参与者在阶段三等待协调者指令超时:
  → 参与者会自动提交事务(因为既然走到了 PreCommit 阶段,说明大家都同意了)
  → 减少了阻塞,但可能导致数据不一致

2PC vs 3PC 对比:

维度2PC3PC
阶段数23(多了 CanCommit 预询问)
参与者超时无(一直等协调者)有(超时自动提交,减少阻塞)
阻塞程度高(协调者挂了就完全阻塞)低(参与者可超时自动决策)
一致性风险有(脑裂导致部分提交)仍有(超时自动提交可能和实际不一致)
实际应用MySQL XA 事务较少使用(复杂且仍不能完全避免不一致)
追问与易错

追问方向:

  • 2PC 的阻塞问题?
  • 3PC 真解决了问题吗?
  • Seata AT 和传统 2PC 区别?

易错点:

  • ❌ 2PC 保证强一致——网络分区时仍可能不一致
  • ❌ 3PC 完美解决了 2PC——超时自动提交可能不一致

💡 记忆锚点

想象婚礼宣誓:2PC 是牧师问双方"你愿意吗"(prepare),都说愿意再宣布结婚(commit),但牧师晕倒全场卡死(单点阻塞);3PC 多加一步"你们打算结婚吗"(canCommit)先轻量探测,且等太久宾客自行散场(超时机制),减少了卡死但仍可能有人没听到结果。