分布式事务之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),并配合消息队列、幂等设计、监控告警,构建健壮的分布式事务体系。

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

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

相关文章

信息收集与搜索引擎

6.1 常见的搜索引擎&#xff08;一、二&#xff09; 6.1.1 通用搜索引擎 Google/Bing&#xff1a; 用途&#xff1a;基础信息收集&#xff08;域名、子域名、敏感文件&#xff09;。 高级语法&#xff1a; site:target.com&#xff1a;限定搜索目标域名。 filetype:pdf&am…

【Java项目测试报告】:在线聊天平台(Online-Chat)

被测试项目已部署&#xff1a;登录页面http://123.249.78.82:8080/login.html 一、项目背景 1.1 测试目标 验证系统功能完整性&#xff0c;确保用户管理、消息传输、好友管理等核心模块符合需求。 1.2 项目技术栈 后端&#xff1a;Spring Boot/Spring MVC/WebSocket 数据…

RAGFlow与Dify的深度刨析

目录 一、RAGFlow 框架 二、Dify 框架 三、两者集成 四、深度对比 1. 核心定位对比 2. 核心功能对比 3. 技术架构对比 4. 部署与成本 5. 适用场景推荐 总结 一、RAGFlow 框架 RAGFlow 是一个专注于深度文档理解和检索增强生成&#xff08;RAG&#xff09;技术的框架…

CQF预备知识:一、微积分 -- 1.2.2 函数f(x)的类型详解

文中内容仅限技术学习与代码实践参考&#xff0c;市场存在不确定性&#xff0c;技术分析需谨慎验证&#xff0c;不构成任何投资建议。 &#x1f4d6; 数学入门全解 本系列教程为CQF(国际量化金融分析师证书)认证所需的数学预备知识&#xff0c;涵盖所有需要了解的数学基础知识…

嵌入式工程师常用软件

1、 Git Git 是公司常用的版本管理工具&#xff0c;人人都要会。在线的 git 教程可以参考菜鸟教程&#xff1a; https://www.runoob.com/git/git-tutorial.html 电子书教程请在搜索栏搜索&#xff1a; git Git 教程很多&#xff0c;常用的命令如下&#xff0c;这些命令可…

TReport组件指南总结

1. TReport 组件简介 TReport 是一个用于生成和打印报表的组件,通常用于连接数据集(如 TDataSet)并设计复杂的报表布局。它支持动态数据绑定、多页报表、分组统计、图表插入等功能。 2. 安装与配置 安装:如果使用的是第三方报表工具(如 Rave Reports),需在 Delphi 中通…

spark任务的提交流程

目录 spark任务的提交流程1. 资源申请与初始化2. 任务划分与调度3. 任务执行4. 资源释放与结果处理附:关键组件协作示意图扩展说明SparkContext介绍 spark任务的提交流程 用户创建一个 Spark Context;Spark Context 去找 Cluster Manager 申请资源同时说明需要多少 CPU 和内…

【C++】C++异步编程四剑客:future、async、promise和packaged_task详解

C异步编程四剑客&#xff1a;future、async、promise和packaged_task详解 1. 引言 1.1 异步编程的重要性 在现代C编程中&#xff0c;异步操作是提高程序性能和响应能力的关键技术。它允许程序在等待耗时操作&#xff08;如I/O、网络请求或复杂计算&#xff09;完成时继续执行…

2021-10-28 C++判断完全平方数

缘由判断一个整数是否为完全平方数-编程语言-CSDN问答 整数用平方法小数用5分法逼近。 int 判断平方数(int n) {//缘由https://ask.csdn.net/questions/7546950?spm1005.2025.3001.5141int a 1;while (a < n / a)if (a*a < n)a;else if (a*a n)return 1;elsereturn 0…

解决weman框架redis报错:Class “llluminatelRedis\RedisManager“ not found

解决weman框架redis报错&#xff1a;Class "llluminatelRedis\RedisManager" not found 报错解决方案 报错 解决方案 按照手册执行 composer require psr/container ^1.1.1 illuminate/redis illuminate/events 安装redis组件 然后restart重启就行了 php webman s…

Windows 11 电源计划进阶——通过异类策略优化大小核CPU调度

一、为什么需要手动控制大小核调度&#xff1f; 1.1 Intel 12/13/14代酷睿与Win11的适配现状 Intel 12代酷睿首次引入混合架构设计&#xff08;P-Core性能核 E-Core能效核&#xff09;&#xff0c;Windows 11虽然原生支持线程调度器&#xff08;Thread Director&#xff09;…

文件系统·linux

目录 磁盘简介 Ext文件系统 块 分区 分组 inode 再谈inode 路径解析 路径缓存 再再看inode 挂载 小知识 磁盘简介 磁盘&#xff1a;一个机械设备&#xff0c;用于储存数据。 未被打开的文件都是存在磁盘上的&#xff0c;被打开的加载到内存中。 扇区&#xff1a;是…

如何使用redis做限流(golang实现小样)

在实际开发中,限流(Rate Limiting)是一种保护服务、避免接口被恶意刷流的常见技术。常用的限流算法有令牌桶、漏桶、固定窗口、滑动窗口等。由于Redis具备高性能和原子性操作,常常被用来实现分布式限流。 下面给出使用Golang结合Redis实现简单限流的几种常见方式(以“固定…

手写ES6 Promise() 相关函数

手写 Promise() 相关函数&#xff1a; Promise()、then()、catch()、finally() // 定义三种状态常量 const PENDING pending const FULFILLED fulfilled const REJECTED rejectedclass MyPromise {/*定义状态和结果两个私有属性:1.使用 # 语法&#xff08;ES2022 官方私有字…

Redis学习专题(五)缓存穿透、缓存击穿、缓存雪崩

目录 一、缓存穿透 缓存穿透的原因&#xff1a; 缓存穿透的现象&#xff1a; 缓存穿透的解决办法&#xff1a; 二、缓存击穿 缓存击穿的原因&#xff1a; 缓存击穿的现象&#xff1a; 缓存击穿的解决办法: 三、缓存雪崩 缓存雪崩的原因&#xff1a; 缓存雪崩的现象&…

【Hadoop】大数据技术之 MapReduce

目录 一、MapReduce概述 1.1 MapReduce 定义 1.2 MapReduce优缺点 1.3 MapReduce 核心思想 1.4 MapReduce 进程 1.5 常用数据序列化类型 1.6 MapReduce 编程规范 二、WordCound 案例 2.1 环境准备 2.2 编写程序 三、MapReduce 工作流程 一、MapReduce概述 1.1 MapRe…

国际前沿知识系列三:解决泛化能力不足问题

目录 国际前沿知识系列三&#xff1a;解决泛化能力不足问题 一、子类建模法与分类建模法在脑区应变预测中的应用 &#xff08;一&#xff09;子类建模法 案例分析 &#xff08;二&#xff09;分类建模法 案例分析 二、基于迁移学习和数据融合的大脑应变预测模型改良 &a…

client.chat.completions.create方法参数详解

response client.chat.completions.create(model"gpt-3.5-turbo", # 必需参数messages[], # 必需参数temperature1.0, # 可选参数max_tokensNone, # 可选参数top_p1.0, # 可选参数frequency_penalty0.0, # 可选参数presenc…

iOS 15.4.1 TrollStore(巨魔商店)安装教程详解:第二篇

🚀 iOS 15.4.1 TrollStore(巨魔商店)安装教程详解 ✨ 前言🛠️ 如何安装 TrollStore?第一步:打开 Safari 浏览器第二步:选择对应系统版本安装方式第三步:访问地址,下载配置文件(plist)第四步:安装配置文件第五步:“jailbreaks.app” 请求安装 TrollHelper第六步…

SQL的RAND用法和指定生成随机数的范围

SQL中的RAND函数能够满足多种随机数生成的需求。通过合理地使用种子、结合一些SQL语句&#xff0c;我们可以实现灵活的随机数生成。在数据填充、数据处理、数据分析中经常需要用RAND生成的随机数。 用法1 生成随机浮点数&#xff0c;其返回值在0&#xff08;包括0&#xff09;…