分布式事务实战:Seata AT模式与TCC模式选型落地

微服务拆分后,跨库跨服务的数据一致性成为绕不开的问题,单体时代的本地事务不再适用。Seata提供AT、TCC、Saga、XA四种模式,其中AT与TCC在业务项目中使用最广。本文对比两种模式的使用方式与适用边界,给出可落地的接入示例。

AT模式:无侵入的自动补偿方案

AT模式对业务代码几乎零侵入:在数据源上包一层代理,分支事务执行前后自动记录undo log快照,回滚时反向补偿。典型用法:

// 引入 seata-spring-boot-starter 并配置数据源代理
@GlobalTransactional(timeoutMills = 30000)
public void createOrder(OrderDTO dto) {
    orderMapper.insert(dto);                 // 本地事务
    stockService.deduct(dto.getSkuId(), 1);  // 远程调用
    couponService.use(dto.getCouponId());
}

@GlobalTransactional标注的入口方法即全局事务起点,分支事务由TC协调二阶段提交。业务方法里不需要写任何补偿逻辑,回滚由undo_log自动完成。

AT模式的代价与适用边界

AT模式适合同一事务内数据一致性要求高、并发冲突概率低的场景。两点限制要先确认:

  • 全局锁:二阶段提交期间对冲突数据加锁,热点商品并发扣减可能放大延迟;
  • 隔离级别:默认读未提交,需要自定义隔离时要在查询上加 SELECT FOR UPDATE 或标记 @GlobalLock。

订单创建、账户积分、库存扣减这类业务,AT模式的成本明显低于手写补偿。

TCC模式:手工补偿控制业务流程

当业务流程中间态必须对外可见、分支事务需要长期持有时,用TCC把每个操作拆成Try、Confirm、Cancel三个阶段:

@TwoPhaseBusinessAction(name = "deductStock",
    commitMethod = "confirm", rollbackMethod = "cancel")
public void deduct(BusinessActionContext ctx, Long skuId, int num) {
    // Try:冻结库存,不直接扣减
    stockMapper.freezeStock(skuId, num);
}

public boolean confirm(BusinessActionContext ctx) {
    // Confirm:冻结转实际扣减,最终提交
    return stockMapper.confirmFreeze(skuId, num);
}

public boolean cancel(BusinessActionContext ctx) {
    // Cancel:解冻恢复
    return stockMapper.releaseFreeze(skuId, num);
}

TCC需要业务方自己保证幂等与资源释放,实现成本比AT高,但适合预占资金、扣减积分、订座等强一致性场景。

两种模式的选型对比

维度 AT模式 TCC模式
侵入性 低,代理数据源即可 高,需拆三个阶段
一致性 最终一致 强一致(资源冻结)
典型场景 订单、库存、积分 资金预占、行程订座
失败恢复 undo自动回滚 人工确认补偿

另一条思路是能不用就不用:事务边界跨越的服务,优先通过幂等接口加本地消息表实现最终一致性,把分布式事务的数量压到极少数,Seata只用于真正强一致的短链路。

生产落地注意事项

Seata服务端(TC)需独立部署并持久化事务日志;客户端事务分组要与服务端配置一致。全局事务超时按最慢链路加余量设置,避免慢接口拖死全局锁。上线前做一次故障演练:kill掉一个分支实例,观察二阶段协调与undo日志是否正常工作。

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/fen-bu-shi-shi-wu-shi-zhan-seataat-mo-shi-yu-tcc-mo-shi/

(0)
小编小编
上一篇 1小时前
下一篇 1小时前

相关推荐