当前位置: 首页 > news >正文

分布式事务之Seata

概述

Seata有四种模式

AT模式:无侵入式的分布式事务解决方案,适合不希望对业务进行改造的场景,但由于需要添加全局事务锁,对影响高并发系统的性能。该模式主要关注多DB访问的数据一致性,也包括多服务下的多DB数据访问一致性问题。通过更新前快照回滚、更新后快照对比在二阶段提交时是否有人修改(为不受Seata代理的数据源做兜底),解决脏写。

优点:

  • 一阶段完成直接提交事务,释放数据库资源,性能比较好

  • 利用全局锁实现读写隔离

  • 没有代码侵入,框架自动完成回滚和提交

缺点:

  • 两阶段之间属于软状态,属于最终一致

  • 框架的快照功能会影响性能,但比XA模式要好很多

TCC模式:高性能的分布式事务解决方案,适用于对性能要求比较高的场景。该模式主要关注业务拆分,在按照业务横向扩展资源时,解决服务间调用的一致性问题。

优点:

  • 一阶段完成直接提交事务,释放数据库资源,性能好
  • 相比AT模型,无需生成快照,无需使用全局锁,性能最强
  • 不依赖数据库事务,而是依赖补偿操作,可以用于非事务型数据库
  • Redis这种也可以使用TCC模式

缺点:

  • 有代码侵入,需要人为编写try、Confirm和Cancel接口,太麻烦
  • 软状态,事务是最终一致
  • 需要考虑Confirm和Cancel的失败情况,做好幂等处理
  • 因为如果失败Seata会重试,所有要做好幂等

Saga模式:长事务的分布式事务解决方案,适用于业务流程长且需要保证事务最终一致性的业务系统。Saga 模式一阶段就会提交本地事务,无锁,长流程情况下可以保证性能,多用于渠道层、集成层业务系统,事务参与者可以是其它公司的服务也可以是遗留系统的服务,并且对于无法进行改造和提供 TCC 要求的接口,也可以使用 Saga 模式。

优点:

  • 一阶段提交本地数据库事务,无锁,高性能;

  • 参与者可以采用事务驱动异步执行,高吞吐;

  • 补偿服务即正向服务的“反向”,易于理解,易于实现;

缺点:

  • Saga 模式由于一阶段已经提交本地数据库事务,且没有进行“预留”动作,所以不能保证隔离性。后续会讲到对于缺乏隔离性的应对措施。

XA模式:强一致性。XA早期版本是一种规范 主流数据库对XA规范提供了支持,没有TM(事务管理者的概念)只有TC和RM。一阶段不提交事务,在第二阶段TM发起事务提交/回滚时才会让TC检查分支状态做提交/回滚因此是强一致性的

优点:

  • 强一致性
  • 易于使用:因为主流数据库都支持且无代码侵入

缺点:

  • 第一阶段不提交,在等待过程中占用数据库锁,占用系统资源,性能差

Seata核心组件

  • TC(Transaction Coordinator):全局事务协调器,负责管理全局事务的状态。
  • TM(Transaction Manager):事务管理器,负责发起全局事务,并向TC注册事务。
  • RM(Resource Manager):资源管理器,负责管理资源的本地事务,并向TC汇报事务状态。

前置条件

  1. 引入Seata依赖:在项目中引入Seata的依赖。
  2. 配置Seata服务:配置Seata的TC服务地址。
  3. 定义全局事务:使用@GlobalTransactional注解定义全局事务。

1. AT 模式(Auto Transaction)​

核心原理

  • ​两阶段提交:

  1. ​阶段一(Branch Commit)​:拦截业务 SQL,生成前置镜像(before image)和后置镜像(after image),保存到 UNDO_LOG 表。
    示例:执行 UPDATE product SET stock = stock - 10 WHERE id = 1 时,记录修改前的 stock=100 和修改后的 stock=90。
  2. 阶段二(Global Commit/Rollback)​:全局事务提交时,删除 UNDO_LOG;回滚时,根据镜像数据生成反向SQL(如 UPDATE product SET stock = 100 WHERE id = 1)。
  • ​全局锁机制:

在阶段一提交前,Seata 会获取记录的全局锁,防止其他事务修改同一数据,确保隔离性。

​应用场景

  • 单服务多数据源:

        例如订单服务同时操作 MySQL 和 PostgreSQL,需要保证两个库的事务一致性。

  • ​简单跨服务调用:

        服务 A 调用服务 B 的接口,两者均使用 AT 模式(如订单服务扣减库存服务)。

代码示例

// 订单服务(使用 AT 模式)
@GlobalTransactional // 开启全局事务
public void saveOrder(OrderRequest request) {// 1. 本地事务:创建订单orderDao.insert(request.getOrder());// 2. 远程调用库存服务(Feign 接口)storageFeign.discount(request.getProductId(), request.getCount());// 3. 模拟异常触发回滚if (request.getForceFail()) {throw new RuntimeException("Force rollback");}
}

关键细节

  • UNDO_LOG 表结构:需在业务库中提前创建,包含 branch_id、xid、rollback_info 等字段。
  • ​隔离性牺牲:AT 模式默认隔离级别为读未提交(Read Uncommitted),高并发场景可能脏读,需业务侧处理(如版本号校验)。
  • ​性能优化:避免单行数据频繁更新,防止全局锁竞争。

​2. TCC 模式(Try-Confirm-Cancel)​

核心原理

三阶段控制:

​Try:预留资源(如冻结库存、预扣余额),完成业务检查。
​Confirm:确认操作,真正执行业务(如扣减冻结的库存)。
​Cancel:回滚操作,释放预留资源(如解冻库存)。

业务侵入性:需手动编写 Try/Confirm/Cancel 接口,处理幂等性、空回滚、悬挂等问题。

​应用场景

  • ​资金交易:转账前预冻结账户金额,最终扣款或解冻。
  • ​第三方服务集成:调用外部 API(如支付接口)需要明确的成功/失败确认。

​代码示例

// TCC 接口定义(账户扣款)
public interface AccountTccService {@TwoPhaseBizAction(name = "deduct", commitMethod = "confirm", rollbackMethod = "cancel")boolean tryDiscount(@BizActionContextParameter(paramName = "userId") String userId,@BizActionContextParameter(paramName = "amount") BigDecimal amount);boolean confirm(BizActionContext context);boolean cancel(BizActionContext context);
}// Try 阶段实现(冻结资金)
@Override
public boolean tryDeduct(String userId, BigDecimal amount) {if (accountDao.getAvailableBalance(userId).compareTo(amount) < 0) {throw new RuntimeException("余额不足");}accountDao.freeze(userId, amount); // 冻结资金return true;
}// Confirm 阶段(实际扣款)
@Override
public boolean confirm(BizActionContext context) {String userId = (String) context.getActionContext("userId");BigDecimal amount = (BigDecimal) context.getActionContext("amount");accountDao.discount(userId, amount);  // 扣减冻结金额accountDao.unfreeze(userId, amount); // 解冻return true;
}// Cancel 阶段(解冻资金)
@Override
public boolean cancel(BizActionContext context) {String userId = (String) context.getActionContext("userId");BigDecimal amount = (BigDecimal) context.getActionContext("amount");accountDao.unfreeze(userId, amount);return true;
}

​关键细节

  • ​幂等性处理:
    通过唯一事务 ID(xid)确保 Confirm/Cancel 只执行一次。
  • ​空回滚问题:
    Try 未执行但收到 Cancel 请求时,需插入标记记录,避免误解冻。
  • ​悬挂问题:
    Cancel 比 Try 先到达时,需通过状态判断拒绝后续 Try 操作。

​3. Saga 模式

​核心原理

  • 事件驱动流程:
    将分布式事务拆分为多个本地事务,每个事务提交后触发下一个事务。若某个事务失败,按反向顺序执行补偿操作。
  • ​补偿机制:
    每个正向操作需定义对应的补偿方法(如 bookHotel() 对应 cancelHotel())。

​应用场景

  • ​长流程业务:
    旅行预订(机票 → 酒店 → 租车)、电商订单(下单 → 支付 → 发货)。
  • 渠道层、集成层业务:
    在渠道层和集成层业务中,往往需要与外部系统进行交互。例如,银行系统与第三方支付平台的集成,或者企业系统与ERP系统的集成。这些场景中,事务的跨服务特性使得Saga模式成为理想的解决方案。
  • ​跨公司服务集成:
    跨公司服务集成中,事务的分布式特性更加明显。例如,一个供应链系统可能涉及多个供应商、物流和零售商的协作。Saga模式通过补偿机制,可以有效地处理这些复杂场景中的事务问题。
  • 最终一致性场景:
    接受中间状态短暂不一致,但最终一致。Saga模式通过补偿操作保证最终一致性。如果某个Saga单元失败,系统会依次调用之前所有单元的补偿操作,回滚之前的操作。例如,如果支付服务扣款失败,系统会调用库存服务的补偿操作恢复库存。

​代码示例

//Saga 流程编排(状态机或注解驱动)
@SagaService
public class OrderSagaService {@Autowiredprivate InventoryService inventoryService;@Autowiredprivate PaymentService paymentService;@SagaStartpublic void createOrder(Order order) {// 1. 扣减库存inventoryService.discount(order.getProductId(), order.getQuantity());// 2. 发起支付paymentService.pay(order.getUserId(), order.getAmount());// 3. 更新订单状态为成功order.setStatus(OrderStatus.SUCCESS);orderDao.update(order);}@Compensatepublic void compensateOrder(Order order) {// 反向操作:释放库存、退款、订单状态回滚inventoryService.restore(order.getProductId(), order.getQuantity());paymentService.refund(order.getUserId(), order.getAmount());order.setStatus(OrderStatus.FAILED);orderDao.update(order);}
}

关键细节

  • ​状态机配置:
    可通过 JSON 或注解定义 Saga 流程,明确每个步骤的补偿方法。
  • ​超时管理:
    设置 Saga 事务超时时间,避免流程长期悬挂。
  • ​异步执行:
    适合结合消息队列(如 RocketMQ)实现异步 Saga。

​注:@Compensate

4. XA 模式

核心原理

  • ​传统两阶段提交:
    ​ Prepare 阶段:所有参与者(数据库)锁定资源,返回就绪状态。
     ​Commit/Rollback 阶段:协调者根据 Prepare 结果提交或回滚。
  • ​强一致性:
    所有资源在 Prepare 阶段锁定,直到全局事务结束。

​应用场景

  • ​金融核心系统:
    银行转账(必须保证双方账户同时成功或失败)。
  • ​传统数据库集成:
    旧系统迁移,依赖数据库原生 XA 协议。

​代码示例

// XA 数据源配置
@Bean
public DataSource dataSource() {MysqlXADataSource xaDataSource = new MysqlXADataSource();xaDataSource.setUrl("jdbc:mysql://localhost:3306/test");xaDataSource.setUser("root");xaDataSource.setPassword("***");return new AtomikosDataSourceBean(xaDataSource);
}// 业务方法(依赖 JTA)
@Transactional // 使用 JTA 事务管理器
public void transfer(String fromId, String toId, BigDecimal amount) {jdbcTemplate.update("UPDATE account SET balance = balance - ? WHERE id = ?", amount, fromId);jdbcTemplate.update("UPDATE account SET balance = balance + ? WHERE id = ?", amount, toId);
}

关键细节

  • ​性能瓶颈:
    全局锁持有时间长,高并发下吞吐量低。
  • ​数据库支持:
    需数据库支持 XA 协议(如 MySQL InnoDB、Oracle)。
  • ​调试复杂:
    XA 事务状态需通过数据库日志或 JTA 工具监控。

选型对比

​对比维度

维度ATTCC    SagaXA
​一致性弱隔离(读未提交)强隔离(预留资源)最终一致性强一致性
​性能高(短事务) 中(两阶段控制)高(异步流程)低(长锁)
​侵入性低(自动 UNDO_LOG)高(手动 TCC 接口)中(补偿方法)低(数据库支持)
适用场景 简单跨服务/多数据源 资金交易、第三方集成长流程业务金融核心、传统系统
​容错能力自动回滚需处理空回滚、悬挂需补偿逻辑完备依赖数据库 XA 恢复

决策树

  • 是否需要强一致性?
    是 → ​XA 模式​(金融场景)或 ​TCC 模式​(业务可控)。
    否 → 进入下一步。
  • ​是否为长流程业务?
    是 → ​Saga 模式​(如电商订单)。
    否 → 进入下一步。
  • ​是否希望低侵入?
    是 → ​AT 模式​(简单跨服务调用)。
    否 → ​TCC 模式​(精细化控制)。

​总结

  • AT 模式:快速解决 80% 的分布式事务问题,适合微服务新手。
  • ​TCC 模式:应对资金、库存等核心资源操作,牺牲开发效率换取高可靠性。
  • ​Saga 模式:长流程业务的终极方案,需接受最终一致性。
  • ​XA 模式:传统系统兼容选择,性能敏感场景慎用。

    实际开发中,多种模式在同一个工程中不可混用、不能同时使用,但可组合使用多种模式(如 AT + Saga),并配合消息队列、幂等设计、监控告警,构建健壮的分布式事务体系。

相关文章:

  • 【MATLAB代码】扩展卡尔曼滤波估计pmsm的位置误差
  • 如何评估物联网框架的交互体验?
  • 五分钟图解Diffusion扩散模型
  • Qt 的多线程
  • JVM—Java对象
  • Vue3中reactive响应式使用注意事项
  • 港口危货储存单位主要安全管理人员考试题
  • Android正则表达式
  • 技术文档:SINAMICS S120 变频器搭配 GRJ9000S 系列 EMC 电源滤波器
  • 教育行业课件共享难题:大文件分发效率优化方案
  • 【Java高阶面经:消息队列篇】22、消息队列核心应用:高并发场景下的解耦、异步与削峰
  • 龙虎榜——20250523
  • 继续对《道德经》第57章至第81章进行数学形式化建模
  • 今日打卡,Leetcode第四题:寻找两个正序数组的中位数,博主表示就会sorted
  • 若依 Plus 自定义字典的使用
  • 如何设置名称服务器
  • 2025年5月软考系分论文预测
  • 【解决】GIT空文件夹不被追踪导致的分支污染
  • 大疆制图跑飞马D2000的正射与三维模型
  • PETR- Position Embedding Transformation for Multi-View 3D Object Detection
  • 免费网站建设itcask/站长之家产品介绍
  • 网站建设制作开发/营销技巧和营销方法心得
  • 餐饮行业网站建设/目前推广平台都有哪些
  • 手机网站建设推广/青岛今天发生的重大新闻
  • 网站备案快吗/深圳推广公司哪家最好
  • 用vs2010做网站并连数据库/百度营销登录