Seata分布式事务实战XATCC模式

目录

XA模式

XA 模式的使用

Spring Cloud Alibaba整合Seata XA

TCC模式

TCC模式接口改造

TCC如何控制异常

Spring Cloud Alibaba整合Seata TCC


XA模式

整体机制

       在 Seata 定义的分布式事务框架内,利用事务资源(数据库、消息服务等)对 XA 协议的支持,以 XA 协议的机制来管理分支事务的一种 事务模式。

            


XA 模式的使用

        编程模型上,XA 模式与 AT 模式保持完全一致。只需要修改数据源代理,即可实现 XA 模式与 AT 模式之间的切换。

@Bean("dataSource")
public DataSource dataSource(DruidDataSource druidDataSource) {// DataSourceProxy for AT mode// return new DataSourceProxy(druidDataSource);// DataSourceProxyXA for XA modereturn new DataSourceProxyXA(druidDataSource);
}

Spring Cloud Alibaba整合Seata XA

对比Seata AT模式配置,只需修改两个地方:

  • 微服务数据库不需要undo_log表,undo_log表仅用于AT模式
  • 修改数据源代码模式为XA模式
seata:# 数据源代理模式 默认ATdata-source-proxy-mode: XA

使用时在事务发起方添加两个事务注解

    @Transactional@GlobalTransactional(name="xxx",rollbackFor=Exception.class)

被调用方添加事务注解

    @Transactional

TCC模式

TCC 基于分布式事务中的二阶段提交协议实现,它的全称为 Try-Confirm-Cancel,即资源预留(Try)、确认操作(Confirm)、取消操作(Cancel),他们的具体含义如下:

  1. Try:对业务资源的检查并预留;
  2. Confirm:对业务处理进行提交,即 commit 操作,只要 Try 成功,那么该步骤一定成功;
  3. Cancel:对业务处理进行取消,即回滚操作,该步骤回对 Try 预留的资源进行释放。

    

XA是资源层面的分布式事务,强一致性,在两阶段提交的整个过程中,一直会持有资源的锁。

TCC是业务层面的分布式事务,最终一致性,不会一直持有资源的锁。

       TCC 是一种侵入式的分布式事务解决方案,以上三个操作都需要业务系统自行实现,对业务系统有着非常大的入侵性,设计相对复杂,但优点是 TCC 完全不依赖数据库,能够实现跨数据库、跨应用资源管理,对这些不同数据访问通过侵入式的编码方式实现一个原子操作,更好地解决了在各种复杂业务场景下的分布式事务问题。

在Seata中,AT模式与TCC模式事实上都是两阶段提交的具体实现,他们的区别在于:

AT 模式基于 支持本地 ACID 事务的关系型数据库:

  • 一阶段 prepare 行为:在本地事务中,一并提交业务数据更新和相应回滚日志记录。
  • 二阶段 commit 行为:马上成功结束,自动异步批量清理回滚日志。
  • 二阶段 rollback 行为:通过回滚日志,自动生成补偿操作,完成数据回滚。

相应的,TCC 模式不依赖于底层数据资源的事务支持:

  • 一阶段 prepare 行为:调用自定义的 prepare 逻辑。
  • 二阶段 commit 行为:调用自定义的 commit 逻辑。
  • 二阶段 rollback 行为:调用自定义的 rollback 逻辑。

简单概括,SEATA的TCC模式就是手工的AT模式,它允许你自定义两阶段的处理逻辑而不依赖AT模式的undo_log。


TCC模式接口改造

       假设现有一个业务需要同时使用服务 A 和服务 B 完成一个事务操作,我们在服务 A 定义该服务的一个 TCC 接口:

public interface TccActionOne {@TwoPhaseBusinessAction(name = "prepare", commitMethod = "commit", rollbackMethod = "rollback")public boolean prepare(BusinessActionContext actionContext, @BusinessActionContextParameter(paramName = "a") String a);public boolean commit(BusinessActionContext actionContext);public boolean rollback(BusinessActionContext actionContext);
}

同样,在服务 B 定义该服务的一个 TCC 接口:

public interface TccActionTwo {@TwoPhaseBusinessAction(name = "prepare", commitMethod = "commit", rollbackMethod = "rollback")public void prepare(BusinessActionContext actionContext, @BusinessActionContextParameter(paramName = "b") String b);public void commit(BusinessActionContext actionContext);public void rollback(BusinessActionContext actionContext);
}

在业务所在系统中开启全局事务并执行服务 A 和服务 B 的 TCC 预留资源方法:

@GlobalTransactional
public String doTransactionCommit(){//服务A事务参与者tccActionOne.prepare(null,"one");//服务B事务参与者tccActionTwo.prepare(null,"two");
}

       TCC 模式同样使用 @GlobalTransactional 注解开启全局事务,而服务 A 和服务 B 的 TCC 接口为事务参与者,Seata 会把一个 TCC 接口当成一个 Resource,也叫 TCC Resource。


TCC如何控制异常

        在 TCC 模型执行的过程中,还可能会出现各种异常,其中最为常见的有空回滚、幂等、悬挂等。Seata 框架在 1.5.1 版本完美解决了这些问题。

如何处理空回滚

        空回滚指的是在一个分布式事务中,在没有调用参与方的 Try 方法的情况下,TM 驱动二阶段回滚调用了参与方的 Cancel 方法。

        要想防止空回滚,那么必须在 Cancel 方法中识别这是一个空回滚,Seata 的做法是新增一个 TCC 事务控制表,包含事务的 XID 和 BranchID 信息,在 Try 方法执行时插入一条记录,表示一阶段执行了,执行 Cancel 方法时读取这条记录,如果记录不存在,说明 Try 方法没有执行。

如何处理幂等

       幂等问题指的是 TC 重复进行二阶段提交,因此 Confirm/Cancel 接口需要支持幂等处理,即不会产生资源重复提交或者重复释放。

       防止幂等问题同样的也是在 TCC 事务控制表中增加一个记录状态的字段 status,该字段有 3 个值,分别为:

  1. tried:1
  2. committed:2
  3. rollbacked:3

       二阶段 Confirm/Cancel 方法执行后,将状态改为 committed 或 rollbacked 状态。当重复调用二阶段 Confirm/Cancel 方法时,判断事务状态即可解决幂等问题。


如何处理悬挂

       悬挂指的是二阶段 Cancel 方法比 一阶段 Try 方法优先执行,由于允许空回滚的原因,在执行完二阶段 Cancel 方法之后直接空回滚返回成功,此时全局事务已结束,但是由于 Try 方法随后执行,这就会造成一阶段 Try 方法预留的资源永远无法提交和释放了。

       解决悬挂问题在 TCC 事务控制表记录状态的字段 status 中增加一个状态:“suspended=4”,当执行二阶段 Cancel 方法时,如果发现 TCC 事务控制表有相关记录,说明二阶段 Cancel 方法优先一阶段 Try 方法执行,因此插入一条 status=4 状态的记录,当一阶段 Try 方法后面执行时,判断 status=4 ,则说明有二阶段 Cancel 已执行,并返回 false 以阻止一阶段 Try 方法执行成功。


Spring Cloud Alibaba整合Seata TCC

业务场景

用户下单,整个业务逻辑由三个微服务构成:

  • 库存服务:对给定的商品扣除库存数量。
  • 订单服务:根据采购需求创建订单。
  • 帐户服务:从用户帐户中扣除余额。

         

1) 环境准备

父pom指定微服务版本

Spring Cloud Alibaba Version

Spring Cloud Version

Spring Boot Version

Seata Version

2.2.8.RELEASE

Spring Cloud Hoxton.SR12

2.3.12.RELEASE

1.5.1

启动Seata Server(TC)端,Seata Server使用nacos作为配置中心和注册中心。

启动nacos服务。

2) 微服务导入seata依赖

spring-cloud-starter-alibaba-seata内部集成了seata,并实现了xid传递。

<!-- seata-->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>

3)微服务application.yml中添加seata配置

seata:application-id: ${spring.application.name}# seata 服务分组,要与服务端配置service.vgroup_mapping的后缀对应tx-service-group: default_tx_groupregistry:# 指定nacos作为注册中心type: nacosnacos:application: seata-serverserver-addr: 127.0.0.1:8848namespace:group: SEATA_GROUPconfig:# 指定nacos作为配置中心type: nacosnacos:server-addr: 127.0.0.1:8848namespace: 7e838c12-8554-4231-82d5-6d93573ddf32group: SEATA_GROUPdata-id: seataServer.properties

注意:请确保client与server的注册中心和配置中心namespace和group一致。

4)定义TCC接口

TCC相关注解如下:

  • @LocalTCC 适用于SpringCloud+Feign模式下的TCC,@LocalTCC一定需要注解在接口上,此接口可以是寻常的业务接口,只要实现了TCC的两阶段提交对应方法便可。
  • @TwoPhaseBusinessAction 注解try方法,其中name为当前tcc方法的bean名称,写方法名便可(全局唯一),commitMethod指向提交方法,rollbackMethod指向事务回滚方法。指定好三个方法之后,seata会根据全局事务的成功或失败,去帮我们自动调用提交方法或者回滚方法。
  • @BusinessActionContextParameter 注解可以将参数传递到二阶段(commitMethod/rollbackMethod)的方法。
  • BusinessActionContext 便是指TCC事务上下文。
/*** 通过 @LocalTCC 这个注解,RM 初始化的时候会向 TC 注册一个分支事务。*/
@LocalTCC
public interface OrderService {/*** TCC的try方法:保存订单信息,状态为支付中** 定义两阶段提交,在try阶段通过@TwoPhaseBusinessAction注解定义了分支事务的 resourceId,commit和 cancel 方法*  name = 该tcc的bean名称,全局唯一*  commitMethod = commit 为二阶段确认方法*  rollbackMethod = rollback 为二阶段取消方法*  BusinessActionContextParameter注解 传递参数到二阶段中*  useTCCFence seata1.5.1的新特性,用于解决TCC幂等,悬挂,空回滚问题,需增加日志表tcc_fence_log*/@TwoPhaseBusinessAction(name = "prepareSaveOrder", commitMethod = "commit", rollbackMethod = "rollback", useTCCFence = true)Order prepareSaveOrder(OrderVo orderVo, @BusinessActionContextParameter(paramName = "orderId") Long orderId);/**** TCC的confirm方法:订单状态改为支付成功** 二阶段确认方法可以另命名,但要保证与commitMethod一致* context可以传递try方法的参数** @param actionContext* @return*/boolean commit(BusinessActionContext actionContext);/*** TCC的cancel方法:订单状态改为支付失败* 二阶段取消方法可以另命名,但要保证与rollbackMethod一致** @param actionContext* @return*/boolean rollback(BusinessActionContext actionContext);
}/*** 通过 @LocalTCC 这个注解,RM 初始化的时候会向 TC 注册一个分支事务。*/
@LocalTCC
public interface StorageService {/*** Try: 库存-扣减数量,冻结库存+扣减数量** 定义两阶段提交,在try阶段通过@TwoPhaseBusinessAction注解定义了分支事务的 resourceId,commit和 cancel 方法*  name = 该tcc的bean名称,全局唯一*  commitMethod = commit 为二阶段确认方法*  rollbackMethod = rollback 为二阶段取消方法*  BusinessActionContextParameter注解 传递参数到二阶段中** @param commodityCode 商品编号* @param count 扣减数量* @return*/@TwoPhaseBusinessAction(name = "deduct", commitMethod = "commit", rollbackMethod = "rollback", useTCCFence = true)boolean deduct(@BusinessActionContextParameter(paramName = "commodityCode") String commodityCode,@BusinessActionContextParameter(paramName = "count") int count);/**** Confirm: 冻结库存-扣减数量* 二阶段确认方法可以另命名,但要保证与commitMethod一致* context可以传递try方法的参数** @param actionContext* @return*/boolean commit(BusinessActionContext actionContext);/*** Cancel: 库存+扣减数量,冻结库存-扣减数量* 二阶段取消方法可以另命名,但要保证与rollbackMethod一致** @param actionContext* @return*/boolean rollback(BusinessActionContext actionContext);
}/*** 通过 @LocalTCC 这个注解,RM 初始化的时候会向 TC 注册一个分支事务。*/
@LocalTCC
public interface AccountService {/*** 用户账户扣款** 定义两阶段提交,在try阶段通过@TwoPhaseBusinessAction注解定义了分支事务的 resourceId,commit和 cancel 方法*  name = 该tcc的bean名称,全局唯一*  commitMethod = commit 为二阶段确认方法*  rollbackMethod = rollback 为二阶段取消方法** @param userId* @param money 从用户账户中扣除的金额* @return*/@TwoPhaseBusinessAction(name = "debit", commitMethod = "commit", rollbackMethod = "rollback", useTCCFence = true)boolean debit(@BusinessActionContextParameter(paramName = "userId") String userId,@BusinessActionContextParameter(paramName = "money") int money);/*** 提交事务,二阶段确认方法可以另命名,但要保证与commitMethod一致* context可以传递try方法的参数** @param actionContext* @return*/boolean commit(BusinessActionContext actionContext);/*** 回滚事务,二阶段取消方法可以另命名,但要保证与rollbackMethod一致** @param actionContext* @return*/boolean rollback(BusinessActionContext actionContext);
}

5)微服务增加tcc_fence_log日志表(解决TCC 幂等、悬挂和空回滚问题)

# tcc_fence_log 建表语句如下(MySQL 语法)
CREATE TABLE IF NOT EXISTS `tcc_fence_log`
(`xid`           VARCHAR(128)  NOT NULL COMMENT 'global id',`branch_id`     BIGINT        NOT NULL COMMENT 'branch id',`action_name`   VARCHAR(64)   NOT NULL COMMENT 'action name',`status`        TINYINT       NOT NULL COMMENT 'status(tried:1;committed:2;rollbacked:3;suspended:4)',`gmt_create`    DATETIME(3)   NOT NULL COMMENT 'create time',`gmt_modified`  DATETIME(3)   NOT NULL COMMENT 'update time',PRIMARY KEY (`xid`, `branch_id`),KEY `idx_gmt_modified` (`gmt_modified`),KEY `idx_status` (`status`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4;

6) 在全局事务发起者中添加@GlobalTransactional注解

核心代码

@GlobalTransactional(name="createOrder",rollbackFor=Exception.class)
public Order saveOrder(OrderVo orderVo) {log.info("=============用户下单=================");log.info("当前 XID: {}", RootContext.getXID());//获取全局唯一订单号  测试使用Long orderId = UUIDGenerator.generateUUID();//阶段一: 创建订单Order order = orderService.prepareSaveOrder(orderVo,orderId);//扣减库存storageFeignService.deduct(orderVo.getCommodityCode(), orderVo.getCount());//扣减余额accountFeignService.debit(orderVo.getUserId(), orderVo.getMoney());return order;
}

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

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

相关文章

【Python从入门到进阶】49、当当网Scrapy项目实战(二)

接上篇《48、当当网Scrapy项目实战&#xff08;一&#xff09;》 上一篇我们正式开启了一个Scrapy爬虫项目的实战&#xff0c;对当当网进行剖析和抓取。本篇我们继续编写该当当网的项目&#xff0c;讲解刚刚编写的Spider与item之间的关系&#xff0c;以及如何使用item&#xff…

【python】0、超详细介绍:json、http

文章目录 一、json二、http2.1 json 读取 request 序列化 三、基本类型3.1 decimal 四、图像4.1 颜色格式转换 一、json import json f open(data.json) # open json file data json.load(f) # 读出 json object for i in data[emp_details]: # 取出一级属性 emp_details, …

云尚办公-0.3.0

5. controller层 import pers.beiluo.yunshangoffice.model.system.SysRole; import pers.beiluo.yunshangoffice.service.SysRoleService;import java.util.List;//RestController&#xff1a;1.该类是控制器&#xff1b;2.方法返回值会被写进响应报文的报文体&#xff0c;而…

ChatRTX安装教程

介于本人一直想将现有的智慧城市的文档结合大模型RAG实现知识库问答助手&#xff0c;借着Chat With RTX的风潮正好将机器人和知识库合二为一&#xff0c;方便以后对众多文件进行查阅。 一、概要 Chat With RTX 是一个 Demo&#xff0c;用来将您自己的资料&#xff08;文档、笔…

第三节:kafka sarama 遇到Bug?

文章目录 前言一、先上结果二、刨根问底总结 前言 前面两节&#xff0c;我们已经简单应用了sarama的两个类型Client和ClusterAdmin&#xff0c;其中有一个案例是获取集群的ControllerId&#xff0c;但是在后面的测试过程过程中&#xff0c;发现一个问题&#xff0c;返回的Cont…

【PyQt5桌面应用开发】3.Qt Designer快速入门(控件详解)

一、Qt Designer简介 Qt Designer是PyQt程序UI界面的实现工具&#xff0c;可以帮助我们快速开发 PyQt 程序的速度。它生成的 UI 界面是一个后缀为 .ui 的文件&#xff0c;可以通过 pyiuc 转换为 .py 文件。 Qt Designer工具使用简单&#xff0c;可以通过拖拽和点击完成复杂界面…

仿12306校招项目业务二(列车检索)

目录 验证数据 加载城市数据 查询列车站点信息 查询列车余票信息 构建列车返回数据 12306 项目中列车数据检索接口路径 &#xfeff; TicketController的pageListTicketQuery&#xfeff;。 GetMapping("/api/ticket-service/ticket/query")public Result<T…

查看笔记本电池健康状态-windows11

在 Windows 11 中获取详细的电池报告 Windows 11 中内置的 Powerfg 命令行选项来生成电池报告。 在任务栏上选择“搜索”&#xff0c;键入“cmd”&#xff0c;长按&#xff08;或右键单击&#xff09;“命令提示符”&#xff0c;然后选择“以管理员身份运行” ->“是”。 …

Mac使用K6工具压测WebSocket

commend空格 打开终端&#xff0c;安装k6 brew install k6验证是否安装成功 k6 version设置日志级别为debug export K6_LOG_LEVELdebug执行脚本&#xff08;进入脚本所在文件夹下&#xff09; k6 run --vus 100 --duration 10m --out csvresult.csv script.js 脚本解释&…

自定义神经网络三之梯度和损失函数激活函数

文章目录 前言梯度概述梯度下降算法梯度下降的过程 optimize优化器 梯度问题梯度消失梯度爆炸 损失函数常用的损失函数损失函数使用原则 激活函数激活函数和损失函数的区别激活函数Relu-隐藏层激活函数Sigmoid和Tanh-隐藏层Sigmoid函数Tanh&#xff08;双曲正切&#xff09; &l…

【前端】nginx 反向代理,实现跨域问题

前面讲跨域的问题&#xff0c;这篇 C# webapi 文章里面已经说过了。在上述文章中是属于从服务器端去允许访问的策略去解决跨域问题。而这里是从客户端的角度利用反向代理的方法去解决跨域问题。 反向代理&#xff1a;其原理就是将请求都接收到一个中间件&#xff08;中间地址&a…

IO 作业 24/2/26

1>思维导图 1> 使用消息队列完成两个进程间相互通信 #include<myhead.h> //定义一个消息类型 struct msgbuf {long mtype; //消息类型char mtext[1024]; //消息正文 }; //定义一个宏&#xff0c;表示消息正文大小 #define MSGSIZE sizeof(struct msgbuf…

人工智能 — 点云模型

目录 一、点云模型1、三维图像2、点云1、概念2、内容 3、点云处理的三个层次1、低层次处理方法2、中层次处理方法3、高层次处理方法 二、Spin image 一、点云模型 1、三维图像 三维图像是一种特殊的信息表达形式&#xff0c;其特征是表达的空间中三个维度的数据。 和二维图像…

荣耀手机如何开启地震预警功能

1、打开荣耀手机&#xff0c;进入“设置”&#xff0c;在搜素栏输入“地震”。 2、进入“安全-应急预警通知”功能栏。 3、开启“地震预警”。 4、查看“预警演示教程”。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/e207e356bb634c11adf926c6a53e48cc.png…

Mysql学习之事务日志redolog深入剖析

Mysql 事务日志 redo log 事务有4种特性&#xff1a;原子性、一致性、隔离性和持久性。那么事务的四种特性到底是基于什么机制实现的呢&#xff1f; 事务的隔离性由锁机制实现。而事务的原子性、一致性和持久性由事务的redo日志和undo日志来保证。 REDO LOG 称为重做日志&…

OpenGL ES (OpenGL) Compute Shader 计算着色器是怎么用的?

OpenGL ES (OpenGL) Compute Shader 是怎么用的? Compute Shader 是 OpenGL ES(以及 OpenGL )中的一种 Shader 程序类型,用于在GPU上执行通用计算任务。与传统的顶点着色器和片段着色器不同,Compute Shader 被设计用于在 GPU 上执行各种通用计算任务,而不是仅仅处理图形…

挑战杯 基于情感分析的网络舆情热点分析系统

文章目录 0 前言1 课题背景2 数据处理3 文本情感分析3.1 情感分析-词库搭建3.2 文本情感分析实现3.3 建立情感倾向性分析模型 4 数据可视化工具4.1 django框架介绍4.2 ECharts 5 Django使用echarts进行可视化展示5.1 修改setting.py连接mysql数据库5.2 导入数据5.3 使用echarts…

供应链大数据:穿越经济迷雾的指南针

随着经济形势的变幻莫测&#xff0c;企业运营面临着前所未有的挑战。在这个充满不确定性的时代&#xff0c;供应链大数据如同一盏明亮的指南针&#xff0c;为企业提供精准的方向指引。下面&#xff0c;我们将深入探讨供应链大数据如何帮助企业洞察市场趋势、优化库存管理、降低…

2.deeplabv3+的主干网络(mobilenet网络)

deeplabv3的论文中用了resnet网络&#xff0c;在这里用轻量级网络mobilenet替换resnet&#xff0c;下面分别是两个网络的代码。 1.mobilenet网络 代码如下&#xff1a; import math import os import cv2 import numpy as np import torch import torch.nn as nn import tor…

基于YOLOv8深度学习+Pyqt5的电动车头盔佩戴检测系统

wx供重浩&#xff1a;创享日记 对话框发送&#xff1a;225头盔 获取完整源码源文件已标注的数据集&#xff08;1463张&#xff09;源码各文件说明配置跑通说明文档 若需要一对一远程操作在你电脑跑通&#xff0c;有偿89yuan 效果展示 基于YOLOv8深度学习PyQT5的电动车头盔佩戴检…