【分布式事务】2PC和TCC区别

2PC和TCC在流程上确实有相似之处(都有“准备-提交”的阶段化操作),但它们的核心设计思想适用场景完全不同。我用一个对比表格+生活比喻帮你彻底理清区别:


核心区别对比表

维度 2PC(两阶段提交) TCC(Try-Confirm-Cancel)
设计目标 保证强一致性(像银行转账) 保证最终一致性(像网购下单)
阶段名称 Prepare + Commit/Rollback Try + Confirm/Cancel
资源锁定方式 数据库自动锁行(底层黑盒) 业务代码手动预留资源(如冻结优惠券)
性能影响 高(全程锁资源,阻塞其他操作) 中(Try阶段后释放锁,Confirm才最终操作)
业务侵入性 低(数据库层面实现,代码无感知) 高(需手动写Try/Confirm/Cancel三个接口)
适用场景 短事务、同构数据库(如MySQL XA) 长事务、跨服务、高并发(如电商下单)
失败处理 依赖数据库回滚 依赖业务补偿(如解冻资金)

生活比喻对比

场景:网购限量商品

  1. 2PC模式(像银行转账):

    • 准备阶段:直接冻结你的钱包余额和商品库存(完全锁定)。
    • 如果支付失败:银行自动解冻余额(自动回滚)。
    • 问题:其他用户在这期间完全不能买这个商品(锁库存)。
  2. TCC模式(像电商实际做法):

    • Try阶段:
      • 扣减虚拟库存(显示“还剩10件”,但实际可超卖)。
      • 冻结你的优惠券(但钱还没扣)。
    • Confirm阶段:
      • 真正扣款,真实库存-1(只有成功支付的用户才会走到这步)。
    • Cancel阶段:
      • 如果支付超时,解冻优惠券,虚拟库存加回去。
    • 优势:其他用户还能看到有货(实际可能超卖,但体验更好)。

关键原理区别图示

2PC的锁机制(数据库自动控制):

flowchart TD A[Prepare] --> B[锁定数据行] B --> C{所有成功?} C -->|是| D[提交并释放锁] C -->|否| E[回滚并释放锁]

TCC的资源预留(业务手动控制):

flowchart TD A[Try] --> B[预留资源: 冻结库存] B --> C{所有成功?} C -->|是| D[Confirm: 真实扣减] C -->|否| E[Cancel: 释放预留]

代码示例对比

2PC(基于MySQL XA):

-- 完全由数据库控制,业务代码简单
XA START 'transaction_id';
UPDATE account SET balance = balance - 100 WHERE user_id = 1;
XA END 'transaction_id';
XA PREPARE 'transaction_id'; -- 准备阶段
XA COMMIT 'transaction_id';  -- 提交阶段

TCC(业务代码实现):

// 需要手动写三个接口
public class OrderService {
    // Try: 预留资源
    public boolean tryCreateOrder(Order order) {
        // 1. 冻结库存(未真实扣减)
        inventoryService.freeze(order.getItemId(), order.getCount());
        // 2. 冻结优惠券
        couponService.lock(order.getCouponId());
        return true;
    }
    
    // Confirm: 真实提交
    public boolean confirmCreateOrder(Order order) {
        // 真实扣减库存
        inventoryService.reduce(order.getItemId(), order.getCount());
        // 真实扣优惠券
        couponService.use(order.getCouponId());
        return true;
    }
    
    // Cancel: 补偿释放
    public boolean cancelCreateOrder(Order order) {
        // 解冻库存
        inventoryService.unfreeze(order.getItemId(), order.getCount());
        // 返还优惠券
        couponService.unlock(order.getCouponId());
        return true;
    }
}

如何选择?

  • 用2PC当

    • 需要强一致性(如金融转账)。
    • 所有参与者是同一个数据库(如MySQL跨表事务)。
  • 用TCC当

    • 跨服务调用(如订单→库存→支付)。
    • 高并发场景(如秒杀,允许最终一致)。
    • 需要避免长事务锁竞争。

一句话总结

  • 2PC是数据库层的“全自动事务”,简单但性能差。
  • TCC是应用层的“手动挡事务”,灵活但要写更多代码。

就像自动挡汽车 vs 手动挡赛车,根据你的路况(业务场景)选合适的! 🚗💨

posted @ 2025-06-12 09:38  佛祖让我来巡山  阅读(166)  评论(0)    收藏  举报

佛祖让我来巡山博客站 - 创建于 2018-08-15

开发工程师个人站,内容主要是网站开发方面的技术文章,大部分来自学习或工作,部分来源于网络,希望对大家有所帮助。

Bootstrap中文网