分布式事务之Seata

news2025/5/25 21:33:32

概述

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 {
    @Autowired
    private InventoryService inventoryService;
    @Autowired
    private PaymentService paymentService;
 
    @SagaStart
    public 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);
    }
 
    @Compensate
    public 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),并配合消息队列、幂等设计、监控告警,构建健壮的分布式事务体系。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2385625.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

推测解码算法在 MTT GPU 的应用实践

前言​ 目前主流的大模型自回归解码每一步都只生成一个token, 尽管kv cache等技术可以提升解码的效率&#xff0c;但是单个样本的解码速度依然受限于访存瓶颈&#xff0c;即模型需要频繁从内存中读取和写入数据&#xff0c;此时GPU的利用率有限。为了解决这种问题&#xff0c;…

Axure酒店管理系统原型

酒店管理系统通常被设计为包含多个模块或界面&#xff0c;以支持酒店运营的不同方面和参与者。其中&#xff0c;管理端和商户端是两个核心组成部分&#xff0c;它们各自承担着不同的职责和功能。 软件版本&#xff1a;Axure RP 9 预览地址&#xff1a;https://556i1e.axshare.…

写实交互数字人在AI招聘中的应用方案

随着科技的进步&#xff0c;越来越多的行业开始探索如何利用人工智能提升效率和服务质量。其中&#xff0c;写实交互数字人技术以其高度拟真的交互体验和丰富的情感表达能力&#xff0c;在人力资源领域特别是招聘环节中展现出了巨大潜力。本文将探讨写实交互数字人在AI招聘中的…

房贷利率计算前端小程序

利率计算前端小程序 视图效果展示如下&#xff1a; 在这里插入代码片 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0&qu…

在Visual Studio中进行cuda编程

首先下载与CUDA Toolkit匹配的Visual Studio版本 比如我的CUDA Toolkit版本是12.6&#xff0c;那么我可以使用2022的Visual Studio。 查看Toolkit版本 nvcc -V 配置 ok&#xff0c;让我们开始Visual Studio的nvcc编译器配置 参考例文https://github.com/apachecn/succinc…

Fastrace:Rust 中分布式追踪的现代化方案

原文链接&#xff1a;Fastrace: A Modern Approach to Distributed Tracing in Rust | FastLabs / Blog 摘要 在微服务架构中&#xff0c;分布式追踪对于理解应用程序的行为至关重要。虽然 tokio-rs/tracing 在 Rust 中被广泛使用&#xff0c;但它存在一些显著的挑战&#xf…

Linux云计算训练营笔记day13【CentOS 7 find、vim、vimdiff、ping、wget、curl、RPM、YUM】

Linux云计算训练营笔记day13[CentOS 7 find、vim、vimdiff、ping、wget、curl、RPM、YUM]] 目录 Linux云计算训练营笔记day13[CentOS 7 find、vim、vimdiff、ping、wget、curl、RPM、YUM]]1.find练习2.vim高级使用2.1 命令模式:2.2 插入模式:2.3 末行模式: 3. vimdiff4. ping5.…

黑马Java基础笔记-15

Set 无索引&#xff0c;无序&#xff0c;不可重复 HashSet object类中默认hashCode的方法是根据地址值。 如果集合中存储的是自定义对象&#xff0c;必须要重写hashCode和equals方法。 底层原理 jdk8以前&#xff1a;数组 链表 jdk8及以后&#xff1a;数组 链表 红黑…

软件设计师“排序算法”真题考点分析——求三连

一、考点分值占比与趋势分析 综合知识题分值统计表 年份考题数量总分值分值占比考察重点2018222.67%时间复杂度/稳定性判断2019334.00%算法特性对比分析2020222.67%空间复杂度要求2021111.33%算法稳定性判断2022334.00%综合特性应用2023222.67%时间复杂度计算2024222.67%分治…

Visual Studio 2019/2022:当前不会命中断点,还没有为该文档加载任何符号。

1、打开调试的模块窗口&#xff0c;该窗口一定要在调试状态下才会显示。 vs2019打开调试的模块窗口 2、Visual Studio 2019提示未使用调试信息生成二进制文件 未使用调试信息生成二进制文件 3、然后到debug目录下看下确实未生成CoreCms.Net.Web.WebApi.pdb文件。 那下面的…

vue--ofd/pdf预览实现

背景 实现预览ofd/pdf超链接功能 业务实现 pdf的预览 实现方式&#xff1a; 直接使用 <iframe :src"${url}#navpanes0&toolbar0" /> 实现pdf的预览。 navpanes0 隐藏侧边栏toolbar0 隐藏顶部工具栏 使用pdf.js&#xff0c;代码先行&#xff1a; <tem…

Python 爬虫之requests 模块的应用

requests 是用 python 语言编写的一个开源的HTTP库&#xff0c;可以通过 requests 库编写 python 代码发送网络请求&#xff0c;其简单易用&#xff0c;是编写爬虫程序时必知必会的一个模块。 requests 模块的作用 发送网络请求&#xff0c;获取响应数据。 中文文档&#xf…

【MySQL】CRUD

CRUD 简介 CRUD是对数据库中的记录进行基本的增删改查操作 Create&#xff08;创建&#xff09;Retrieve&#xff08;读取&#xff09;Update&#xff08;更新&#xff09;Delete&#xff08;删除&#xff09; 一、新增&#xff08;Create&#xff09; 语法&#xff1a; I…

Spring Boot微服务架构(三):Spring Initializr创建CRM项目

使用Spring Initializr创建CRM项目 一、创建项目前的准备 访问Spring Initializr网站&#xff1a; 打开浏览器访问 https://start.spring.io/或者直接使用IDE&#xff08;如IntelliJ IDEA或Eclipse&#xff09;内置的Spring Initializr功能 项目基本信息配置&#xff1a; Proj…

【笔记】PyCharm 中创建Poetry解释器

#工作记录 在使用 PyCharm 进行 Python 项目开发时&#xff0c;为项目配置合适的 Python 解释器至关重要。Poetry 作为一款强大的依赖管理和打包工具&#xff0c;能帮助我们更便捷地管理项目的依赖项与虚拟环境。下面将详细记录在 PyCharm 中创建 Poetry 解释器的步骤。 前提条…

python中的numpy(数组)

&#xff08;0&#xff09;numpy介绍 NumPy是Python中用于科学计算的基础库&#xff0c;提供高效的多维数组对象ndarray&#xff0c;支持向量化运算&#xff0c;能大幅提高数值计算效率。它集成了大量数学函数&#xff08;如线性代数、傅里叶变换等&#xff09;&#xff0c;可…

rce命令执行原理及靶场实战(详细)

2. 原理 在根源上应用系统从设计上要给用户提供一个指定的远程命令操作的接口。漏洞主要出现在常见的路由器、防火墙、入侵检测等设备的web管理界面上。在管理界面提供了一个ping服务。提交后&#xff0c;系统对该IP进行ping&#xff0c;并且返回结果。如果后台服务器并没有对…

Fuzz 模糊测试篇JS 算法口令隐藏参数盲 Payload未知文件目录

1 、 Fuzz 是一种基于黑盒的自动化软件模糊测试技术 , 简单的说一种懒惰且暴力的技术融合了常见 的以及精心构建的数据文本进行网站、软件安全性测试。 2 、 Fuzz 的核心思想 : 口令 Fuzz( 弱口令 ) 目录 Fuzz( 漏洞点 ) 参数 Fuzz( 利用参数 ) PayloadFuzz(Bypass)…

展示了一个三轴(X, Y, Z)坐标系!

等轴测投影”&#xff08;isometric projection&#xff09;风格的手绘风格三维图&#xff0c;即三条坐标轴&#xff08;x₁, x₂, x₃&#xff09;看起来彼此垂直、等角分布&#xff08;通常是 120 夹角&#xff09;&#xff0c;它是常见于教材和数学书籍的 “假三维”表示法。…

【b站计算机拓荒者】【2025】微信小程序开发教程 - chapter1 初识小程序 - 3项目目录结构4快速上手

3 项目目录结构 3.1 项目目录结构 3.1.1 目录介绍 # 1 项目主配置文件&#xff0c;在项目根路径下&#xff0c;控制整个项目的-app.js # 小程序入口文件&#xff0c;小程序启动&#xff0c;会执行此js-app.json # 小程序全局配置文件&#xff0c;配置小程序导航栏颜色等信息…