【SpringCloud】使用Seata实现分布式事务

目录

    • 一、Seata 框架的需求背景
    • 二、Seata 事务模式与架构
      • 2.1 Seata 组成
      • 2.2 Seata 事务模式
    • 三、Seata 实战演示
      • 3.1 部署 Seata Server
        • 3.1.1 下载 Seata Server
        • 3.1.2 更改 Seata Server 配置
        • 3.1.3 创建 Seata Server 所需的数据库、数据库表
        • 3.1.4 启动 Seata Server
      • 3.2 Seata AT 模式分布式事务数据一致性演示
        • 3.2.1 添加依赖
        • 3.2.2 在项目中配置 Seata
        • 3.2.2 项目中使用 Seata AT 模式

一、Seata 框架的需求背景

一般情况下,在 Java 项目中如果存在对一个数据库实例的一系列操作的,为了避免程序执行过程中出现异常,我们通常会使用一个事务包裹住这一系列数据库操作,从而保证这一组操作的数据安全。我们通常使用Spring工具箱中的工具来实现本地事务(例如 @Transactional 注解提供的声明式事务功能等)。
但是,在微服务架构下,一个微服务可能存在多个实例,或者说一个微服务实例在运行期间可能同时对多个数据库实例进行CRUD。在这种分布式应用场景下,使Spring工具箱内的工具就失效了。我们需要借助分布式事务来保证分布式应用场景下的数据一致性。Seata 提供了分布式事务完备的解决方案,针对不同的分布式事务场景有不同的模式。

二、Seata 事务模式与架构

2.1 Seata 组成

Seata 框架由三个组件组成,分别是事务协调器(Transaction Coordinator,简称TC),事务管理器(Transaction Manager,简称TM),资源管理器(Resource Manager,简称RM)。

  • 事务协调器(TC):是一个中心化的事务协调者的角色,主要用来协调全局事务的提交和回滚,并管理全局事务与分支事务的状态。是一个需要独立部署的服务,也就是我们下面要进行部署的 Seata Server;
  • 事务管理器(TM):主要用来发起一个全局事务,对一个全局事务是提交,还是回滚做出决议。在我们实际的项目中,
  • 资源管理器(RM):操作分支事务进行提交或者回滚,并向事务协调器(TC)上报分支事务的状态。

在这里插入图片描述
以上图为例来介绍下 Seata 的架构。 事务协调器(TC,又被叫做 Seata Server)是需要被独立部署的,在AT 模式下,TM 和 RM 则是在相应的微服务中引入依赖,添加相应的配置,在需要发起全局事务的方法上添加相应的注解即可。

  • 上图在 Business 微服务模块中发起一个全局事务,并将该全局事务注册到 TC 上;
  • Business 微服务模块调用了 Stock 微服务和 Order 微服务,Stock 微服务和 Order 微服务都属于该全局事务下的分支事务,这2个被调用的微服务执行本地事务并生成相应的回滚日志到undolog数据库表中,执行完成之后(无论成功或失败)也会向 TC 上报分支事务执行情况。
  • 在 Order 微服务中又调用了 Account 微服务,又开启了一个分支事务,Account 微服务执行本地事务并生成相应的回滚日志到undolog数据库表中,执行完毕之后向 TC 上报自己所在的分支事务执行状态。
  • Business 微服务对全局事务的执行结果进行决议,如果所有的分支事务都执行成功,则提交全局事务,否则,会根据undolog数据库表中记录的回滚日志,对所有执行成功的分支事务进行回滚。

2.2 Seata 事务模式

模式类型数据一致性性能业务侵入性适用场景
AT 模式弱一致性无侵入大多数分布式事务场景,要求无须改造业务代码,快速接入时
XA 模式强一致性无侵入想要迁移到 Seata 平台基于 XA 协议的老应用,使用 XA 模式将更平滑
Saga 模式最终一致性很高有侵入,需要实现状态机及补偿代码业务流程长、业务流程多,或者遗留系统服务,无法提供TCC要求的3个接口
TCC 模式弱一致性很高有侵入,需要实现try,confirm,cancel 3个接口适用于核心系统等对性能有很高要求的场景

三、Seata 实战演示

下面演示 AT 模式下的 Seata 使用。分为2各部分:部署 Seata Server,分布式事务的数据一致性。

3.1 部署 Seata Server

3.1.1 下载 Seata Server

在 Seata 的 Github 主页的 Release 页面下载对应版本的二进制压缩包。
在这里插入图片描述

3.1.2 更改 Seata Server 配置

默认的 Seata Server 无法运行,需要更改配置,这里的 Seata Server 将使用 MySQL 数据库作为数据源,使用 Nacos 作为服务发现、注册中心。
首先,在Seata Server 的conf 目录下找到文件 file.conf.example 复制一份,并将文件名改为 file.conf,打开该文件进行更改,改动主要集中在 store 节点:

store {## store mode: file、dbmode = "db"## database store propertydb {## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp) etc.datasource = "druid"## 配置的数据库类型dbType = "mysql"## 数据库连接驱动driverClassName = "com.mysql.jdbc.Driver"## 数据库连接 URLurl = "jdbc:mysql://127.0.0.1:3306/seata?rewriteBatchedStatements=true"## 数据库连接账号密码user = "fuyou"password = "fuyou3323"## 数据库连接配置minConn = 5maxConn = 50## Seata Server在数据库表中存放全局事务锁信息的表名globalTable = "global_table"## Seata Server在数据库表中存放分支事务锁信息的表名branchTable = "branch_table"lockTable = "lock_table"queryLimit = 100}
}

以上配置的主要更改点是,把mode字段取值改为db,然后就是数据库相关的配置,设置数据库类型,数据库驱动,数据库连接的URL,数据库的账号密码,以及 Seata Server 存储全局锁及表所的数据库表名。

接下来接着更改 registry.conf 文件里的配置,内容大概如下:

registry {# 支持 file 、nacos 、eureka、redis、zk、consul、etcd3、sofatype = "nacos"nacos {application = "seata-server"serverAddr = "127.0.0.1:8848"group = "myGroup"namespace = "public"cluster = "default"username = ""password = ""}
}

因为我们使用 Nacos 进行服务的注册发现,因此我们将Seata Server也注册到 Nacos 上进行服务管理和使用(当然,你也可以选择其他类型的注册中心)。上述配置主要是配置了 注册中心的类型,Seata Server的服务名,Nacos的地址、服务组等信息。

3.1.3 创建 Seata Server 所需的数据库、数据库表

我们在上面配置了 Seata Server 中使用MySQL数据库进行存储,并在 URL 中配置了 Seata Server 使用的数据库库名为 seata。Seata Server(TC)在运行期间,需要管理协调全局事务和分支事务,在这个过程需要把一些信息存在数据库中,例如XID(全局事务ID),分支事务ID等信息。
为了避免资源的竞争,Seata也会为资源加锁,避免不同的全局事务之间抢占资源。例如,一个分支事务只有在获取到全局锁和本地锁的情况下才可以提交成功对应的分支事务,并将对应的回滚日志写到数据库中。全局锁和本地锁的相关信息就存在名为 seata 的数据库的 lock_table 表中。

-- the table to store GlobalSession data
CREATE TABLE IF NOT EXISTS `global_table`
(`xid`                       VARCHAR(128) NOT NULL,`transaction_id`            BIGINT,`status`                    TINYINT      NOT NULL,`application_id`            VARCHAR(32),`transaction_service_group` VARCHAR(32),`transaction_name`          VARCHAR(128),`timeout`                   INT,`begin_time`                BIGINT,`application_data`          VARCHAR(2000),`gmt_create`                DATETIME,`gmt_modified`              DATETIME,PRIMARY KEY (`xid`),KEY `idx_gmt_modified_status` (`gmt_modified`, `status`),KEY `idx_transaction_id` (`transaction_id`)) ENGINE = InnoDBDEFAULT CHARSET = utf8mb4;-- the table to store BranchSession data
CREATE TABLE IF NOT EXISTS `branch_table`
(`branch_id`         BIGINT       NOT NULL,`xid`               VARCHAR(128) NOT NULL,`transaction_id`    BIGINT,`resource_group_id` VARCHAR(32),`resource_id`       VARCHAR(256),`branch_type`       VARCHAR(8),`status`            TINYINT,`client_id`         VARCHAR(64),`application_data`  VARCHAR(2000),`gmt_create`        DATETIME,`gmt_modified`      DATETIME,PRIMARY KEY (`branch_id`),KEY `idx_xid` (`xid`)) ENGINE = InnoDBDEFAULT CHARSET = utf8mb4;-- the table to store lock data
CREATE TABLE IF NOT EXISTS `lock_table`
(`row_key`        VARCHAR(128) NOT NULL,`xid`            VARCHAR(96),`transaction_id` BIGINT,`branch_id`      BIGINT       NOT NULL,`resource_id`    VARCHAR(256),`table_name`     VARCHAR(32),`pk`             VARCHAR(36),`gmt_create`     DATETIME,`gmt_modified`   DATETIME,PRIMARY KEY (`row_key`),KEY `idx_branch_id` (`branch_id`)) ENGINE = InnoDBDEFAULT CHARSET = utf8mb4;

本地创建库表情况如下:
在这里插入图片描述

除了 Seata Server 要使用的数据库及数据库表以外,还需要在引入 Seata 依赖的 client 侧的微服务所使用的数据库内,创建一个数据库表undo_log,这个就是 Seata 的回滚日志表,每个执行成功的分支事务都需要将该分支对应的回滚日志写入到该表中,如果全局事务回滚时,每个分支事务就根据分支事务的回滚日志进行恢复。

CREATE TABLE IF NOT EXISTS `undo_log`
(`id`            BIGINT(20)   NOT NULL AUTO_INCREMENT COMMENT 'increment id',`branch_id`     BIGINT(20)   NOT NULL COMMENT 'branch transaction id',`xid`           VARCHAR(100) NOT NULL COMMENT 'global transaction id',`context`       VARCHAR(128) NOT NULL COMMENT 'undo_log context,such as serialization',`rollback_info` LONGBLOB     NOT NULL COMMENT 'rollback info',`log_status`    INT(11)      NOT NULL COMMENT '0:normal status,1:defense status',`log_created`   DATETIME     NOT NULL COMMENT 'create datetime',`log_modified`  DATETIME     NOT NULL COMMENT 'modify datetime',PRIMARY KEY (`id`),UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)) ENGINE = InnoDBAUTO_INCREMENT = 1DEFAULT CHARSET = utf8mb4 COMMENT ='AT transaction mode undo table';
3.1.4 启动 Seata Server

在解压好的Seata Server 目录内,切换到 /bin 目录下,运行 Seata Server 的启动脚本。
在这里插入图片描述
启动成功后,效果大致如下:

在这里插入图片描述

PS :
1. 因为 Seata 要注册到 Nacos 上,所以在启动Seata Server之前务必先确保Nacos服务在线(你也可以选择其他类型的注册中心,因为我使用的是Nacos,所以需要确保Nacos在线);
2. 尽量确保 seata server 的 /lib 目录内依赖的mysql 驱动的版本与本地安装的数据库版本一致,或者相近,否则可能会有报错;

3.2 Seata AT 模式分布式事务数据一致性演示

3.2.1 添加依赖

接下来我们要演示 Seata 的 AT 模式下可以保证分布式事务的数据一致性。对于 Seata 来说微服务侧是 client 端,我们首先需要先添加 Seata 依赖:

<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
3.2.2 在项目中配置 Seata

在需要使用Seata的每个微服务的 application.yaml 文件中添加 Seata 的配置项:

spring:cloud:alibaba:seata:tx-service-group: seata-server-groupseata:application-id: orderregistry:type: nacosnacos:application: seata-serverserver-addr: localhost:8848namespace: devgroup: myGroupcluster: defaultservice:vgroup-mapping:seata-server-group: default
3.2.2 项目中使用 Seata AT 模式

因为 Seata 的 AT 模式是无侵入的,我们只需要在开启分布式事务的方法上添加 @GlobalTransactional 注解即可。示例代码如下:

	@DeleteMapping("order")@GlobalTransactional(name = "business", rollbackFor = Exception.class)public void deleteOrder(@RequestParam("orderId") Long orderId) {customerService.deleteOrder(orderId);}@Override@Transactionalpublic void deleteOrder(Long orderId) {stockService.recoverStock(orderId);orderService.deleteOrder(orderId);// 执行到此处显式抛出异常throw new RuntimeException("Branch transaction exception.");}

在以上演示代码的 deleteOrder 方法中,调用了 stockService 服务的 deleteOrder,此处是一个 openFeign 的远程调用。不属于本地的事务。如果调用该方法后,还发现订单未删除,说明分布式事务生效了,该全局事务下的所有分支事务都进行了回滚。

我在本地新下了一个订单,系统生成的订单ID 为 8.

在这里插入图片描述

然后调用上述代码中提供的订单删除接口。
在这里插入图片描述

再次查询订单ID 为 8 的订单,发现并该订单还在。
在这里插入图片描述
以上就是 seata 框架 AT 模式下的演示。Seata 的 AT模式对业务无侵入,不用对项目代码进行改造,只需要在对应位置处加上相应注解即可。改造工作量很小。

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

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

相关文章

php作为服务器端语言,处理网页没有问题,但是gui就差了点。先看一下主流的gui框架有哪些

其他php桌面应用程序 1 PHP 程序打包为桌面应用-PHPDesktop 的 Linux 版本介绍 2 nativephp 3 借助 js 还可以用electron 还是tauri 除了wxWidgets和Qt&#xff0c;还有许多其他的GUI框架可供选择&#xff0c;每个框架都有其独特的优势和缺点。以下是一些常见的GUI框架及其特…

C++ 变量类型

C 变量类型 变量其实只不过是程序可操作的存储区的名称。C 中每个变量都有指定的类型&#xff0c;类型决定了变量存储的大小和布局&#xff0c;该范围内的值都可以存储在内存中&#xff0c;运算符可应用于变量上。 变量的名称可以由字母、数字和下划线字符组成。它必须以字母…

Fabric.js在vue2中使用

Fabric.js安装 这里我是基于vue来使用的&#xff0c;先安装上Fabric.js npm install fabric 在main.js中 import fabric from fabric Vue.use(fabric);Fabric 提供了 7 种基础形状&#xff1a; fabric.Circle (圆)fabric.Ellipse (椭圆)fabric.Line (线)fabric.Polyline (多条…

伊理威科技:抖音店铺运营好做吗

在数字营销的浪潮中&#xff0c;抖音以其强大的用户基础和独特的算法推荐机制成为了众多商家眼中的“香饽饽”。然而&#xff0c;对于许多初涉此领域的商家来说&#xff0c;心中不免有这样的疑问&#xff1a;“抖音店铺运营好做吗?” 运营一个抖音店铺并非易事。它既需要创意的…

【C语言】守护进程(daemon)的输出到一个文本文件

一、常用的守护进程函数 void daemonize () {//deamonizepid_t pid fork();if( pid > 0 ){ //parent exitexit(0);}//child continuesetsid();chdir("/");close(0);open("/dev/null", O_RDWR);//no env debugif(!getenv("debug")){cl…

Spring 拦截器实现请求拦截与参数处理【拦截器(Interceptor)和过滤器(Filter)的区别】

业务场景&#xff1a; 项目中需要使用请求头传输一个密文字符串&#xff0c;后端服务获取密文字符串后&#xff0c;进行解密验证&#xff0c;然后执行响应的业务&#xff0c;这里有好几个接口都用需要使用这个密文字符串&#xff0c;如果我们在每个接口中进行校验处理&#xff…

AI预测福彩3D第13弹【2024年3月20日预测--第3套算法重新开始计算第3次测试】

今天咱们继续对第3套算法进行第3次测试&#xff0c;第3套算法加入了012路的权重。废话不多说了&#xff0c;直接上结果吧~ 最终&#xff0c;经过研判分析&#xff0c;2024年3月20日福彩3D的七码预测结果如下&#xff1a; 百位&#xff1a;7 4 8 3 6 9 0&#xff08;5换0&#x…

锂电池寿命预测 | Matlab基于ALO-SVR蚁狮优化支持向量回归的锂离子电池剩余寿命预测

目录 预测效果基本介绍程序设计参考资料 预测效果 基本介绍 锂电池寿命预测 | Matlab基于ALO-SVR蚁狮优化支持向量回归的锂离子电池剩余寿命预测 基于蚁狮优化和支持向量回归的锂离子电池剩余寿命预测: 1、提取NASA数据集的电池容量&#xff0c;以历史容量作为输入&#xff0c;…

Java项目:66 ssm实验室耗材管理系统设计与实现+jsp

作者主页&#xff1a;源码空间codegym 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 管理员管理实验材料&#xff0c;审核教师与学生对实验材料的申请信息&#xff0c;统计每学年实验材料的使用总数信息。 教师申请使用实验材料…

【探索Linux】—— 强大的命令行工具 P.28(网络编程套接字 —— 简单的UDP网络程序模拟实现)

阅读导航 引言一、UDP协议二、UDP网络程序模拟实现1. 预备代码⭕makefile文件⭕打印日志文件⭕打开指定的终端设备文件&#xff0c;并将其作为标准错误输出的目标文件描述符 2. UDP 服务器端实现&#xff08;UdpServer.hpp&#xff09;3. UDP 客户端实现&#xff08;main函数&a…

day04vue学习

day04 一、学习目标 1.组件的三大组成部分&#xff08;结构/样式/逻辑&#xff09; ​ scoped解决样式冲突/data是一个函数 2.组件通信 组件通信语法父传子子传父非父子通信&#xff08;扩展&#xff09; 3.综合案例&#xff1a;小黑记事本&#xff08;组件版&#xff09…

全量知识系统的核心-全量知识的一个“恰当组织”的构想及百度AI答问

全量知识系统的核心-全量知识的一个恰当组织 Q1. 以下是对 我刚刚完成的文档“全量知识系统的核心&#xff1a;全量知识的一个恰当组织构想”的百度AI答复。由于字数400的限制&#xff0c;内容被分成四段. 第一次回答&#xff1a;学科和科学的框架 关于技术学科、一般学科和…

DeprecationWarning: isDaemon() is deprecated, get the daemon attribute instead

报错处理 # t.setDaemon(True) # 阙辉注释 t.daemonTrue # 阙辉新增

已有TensorFlow安装包新建相应python版本的虚拟环境

已有TensorFlow安装包新建虚拟环境 新建conda虚拟环境 新建的虚拟环境默认在Anaconda安装目录D:\Anaconda3\envs&#xff08;根据自己的安装目录看&#xff09; 切换到新建的虚拟环境 在这里可以直接安装下载好的TensorFlow安装包 检查是否安装好 输入python进入python环境…

YOLOv7 | 添加GSConv,VoVGSCSP等多种卷积,有效提升目标检测效果,代码改进(超详细)

⭐欢迎大家订阅我的专栏一起学习⭐ &#x1f680;&#x1f680;&#x1f680;订阅专栏&#xff0c;更新及时查看不迷路&#x1f680;&#x1f680;&#x1f680; YOLOv5涨点专栏&#xff1a;http://t.csdnimg.cn/QdCj6 YOLOv7专栏&#xff1a; http://t.csdnimg.cn/dy…

《论文阅读》端到端情感原因对提取的有效子句间建模

《论文阅读》端到端情感原因对提取的有效子句间建模 前言简介模型架构Document EncodingInter-Clause Relationship ModelingClause Pair Representation Learning and Ranking损失函数问题前言 亲身阅读感受分享,细节画图解释,再也不用担心看不懂论文啦~ 无抄袭,无复制,纯…

浙政钉埋点:深入解析与应用实践

一、引言 在数字化时代&#xff0c;数据已经成为驱动业务发展的重要动力。对于政府机构而言&#xff0c;如何有效收集、分析和利用数据&#xff0c;以提升公共服务质量和效率&#xff0c;已成为一项重要课题。浙政钉作为浙江省政府推出的数字化协同办公平台&#xff0c;其埋点…

使用Python实现凯撒密码加密

凯撒密码&#xff08;Caesar Cipher&#xff09;是一种简单的替换式密码&#xff0c;其加密原理是将明文中的每个字符按照一定的偏移量进行替换&#xff0c;从而得到密文。在Python中&#xff0c;我们可以使用内置的字符串函数和循环结构来实现凯撒密码的加密过程。 以下是一个…

使用nginx搭建的文件服务器一直提示 404 Not Found ,是文件不存在还是没有权限?

使用nginx搭建一个简单的文件服务器&#xff0c;配置如下 user root; worker_processes auto; error_log /var/log/nginx/error.log; pid /run/nginx.pid;# Load dynamic modules. See /usr/share/nginx/README.dynamic. include /usr/share/nginx/modules/*.conf;events {wor…

mapbox 获取当前比例尺 scale

一、mapbox中提供了比例尺控件&#xff0c;在创建地图后可使用此方式显示比例尺控件 map.addControl(new mapboxgl.ScaleControl(), bottom-left) 可通过修改css改变自带比例尺样式 二、计算得出当前scale&#xff0c; 具体代码可在mapbox源码中查看&#xff0c;此处仅以单位M…