首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >分布式事务解决方案:Seata TCC模式与Saga模式,哪个更适合你的业务场景?

分布式事务解决方案:Seata TCC模式与Saga模式,哪个更适合你的业务场景?

作者头像
格姗知识圈
发布2025-06-19 09:55:03
发布2025-06-19 09:55:03
43600
代码可运行
举报
文章被收录于专栏:格姗知识圈格姗知识圈
运行总次数:0
代码可运行

那是一个月黑风高的晚上,我正准备下班,突然运营同事急冲冲跑过来:"用户下单付款成功了,但是库存没扣减,订单状态还是待支付!"我的内心瞬间凉了半截,这不是典型的分布式事务问题吗?

说起分布式事务,相信很多人都被它折磨过。微服务架构下,一个业务操作往往涉及多个服务,如何保证数据一致性成了让人头疼的问题。今天就聊聊Seata框架中的两种主流解决方案:TCC模式Saga模式

TCC:手动挡,但是精确控制

TCC(Try-Confirm-Cancel)模式就像开手动挡的车,操作复杂但控制精准。它要求每个参与方都实现三个接口:

Try阶段:预留资源,比如冻结库存而不是直接扣减 Confirm阶段:真正执行业务,确认扣减库存 Cancel阶段:释放资源,解冻库存

代码语言:javascript
代码运行次数:0
运行
复制
@TccAction
public class InventoryTccAction {

    @TwoPhaseBusinessAction(name = "freezeInventory")
    public boolean freezeInventory(@BusinessActionContextParameter("productId") Long productId,
                                   @BusinessActionContextParameter("quantity") Integer quantity) {
        // Try:冻结库存,不是真正扣减
        return inventoryService.freezeStock(productId, quantity);
    }

    public boolean confirm(BusinessActionContext context) {
        // Confirm:确认扣减库存
        Long productId = (Long) context.getActionContext("productId");
        Integer quantity = (Integer) context.getActionContext("quantity");
        return inventoryService.confirmDeduct(productId, quantity);
    }

    public boolean cancel(BusinessActionContext context) {
        // Cancel:解冻库存
        Long productId = (Long) context.getActionContext("productId");
        Integer quantity = (Integer) context.getActionContext("quantity");
        return inventoryService.unfreezeStock(productId, quantity);
    }
}

TCC的好处是强一致性,要么全成功要么全回滚,数据不会出现中间状态。但代价也很明显:

  • 每个服务都要实现三套接口,开发成本高
  • 需要考虑各种异常情况,比如Cancel失败怎么办
  • 对业务侵入性强,几乎要重写所有业务逻辑

我曾经用TCC改造过一个电商订单系统,光是处理各种边界情况就花了两个月,代码复杂度翻了好几倍。

Saga:自动挡,适合长流程

Saga模式就像自动挡汽车,使用简单但控制力稍弱。它把一个分布式事务拆分成多个本地事务,每个本地事务都有对应的补偿事务

Seata支持两种Saga实现方式:

状态机模式:通过JSON配置定义事务流程 注解模式:直接在方法上加注解

代码语言:javascript
代码运行次数:0
运行
复制
@SagaOrchestration
public class OrderSagaOrchestrator {

    @SagaOrchestrationStart
    public void processOrder(OrderRequest request) {
        // 开始Saga事务
    }

    @SagaTask(compensationMethod = "cancelPayment")
    public PaymentResult makePayment(OrderRequest request) {
        return paymentService.pay(request);
    }

    public void cancelPayment(OrderRequest request) {
        // 补偿:退款
        paymentService.refund(request.getOrderId());
    }

    @SagaTask(compensationMethod = "restoreInventory")
    public void deductInventory(OrderRequest request) {
        inventoryService.deduct(request.getProductId(), request.getQuantity());
    }

    public void restoreInventory(OrderRequest request) {
        // 补偿:恢复库存
        inventoryService.restore(request.getProductId(), request.getQuantity());
    }
}

Saga的优势很明显:

  • 最终一致性足以满足大多数业务场景
  • 对现有业务代码侵入小,主要是增加补偿逻辑
  • 天然支持长事务,不会长时间锁定资源

但也有坑需要注意:会出现中间状态,用户可能看到订单已创建但库存还没扣减的情况。

选择建议:因地制宜,没有银弹

经过几年的实战经验,我总结了一套选择规则:

选TCC的场景:

  • 金融交易、支付等对一致性要求极高的场景
  • 事务链路短,参与方少(建议不超过3个)
  • 团队有足够的开发资源和维护能力

选Saga的场景:

  • 电商下单、物流跟踪等业务流程复杂的场景
  • 对性能要求高,不能长时间锁定资源
  • 可以接受短暂的数据不一致

还有个实用技巧:混合使用。核心链路用TCC保证强一致性,外围流程用Saga提升性能。比如订单支付用TCC,发送短信通知用Saga。

踩坑血泪史

说个我踩过的坑:早期使用Saga时,没考虑补偿操作的幂等性。结果一个补偿操作被重复执行,用户收到了两次退款。从那以后,我所有的补偿操作都会先检查状态,避免重复执行。

代码语言:javascript
代码运行次数:0
运行
复制
public void cancelPayment(OrderRequest request) {
    // 先检查状态,避免重复退款
    if (paymentService.isRefunded(request.getOrderId())) {
        return;
    }
    paymentService.refund(request.getOrderId());
}

还有个容易忽视的点:监控和告警。分布式事务涉及多个服务,出问题时排查难度极大。建议为每个事务分配唯一ID,记录详细的执行日志,这样出问题时能快速定位。

分布式事务没有完美方案,只有最适合当前业务的选择。你在项目中用过哪种方案?遇到过什么坑?

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-06-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 格姗知识圈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • TCC:手动挡,但是精确控制
  • Saga:自动挡,适合长流程
  • 选择建议:因地制宜,没有银弹
  • 踩坑血泪史
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档