网站首页 > 教程文章 正文
- 事务,TC 就会创建一个全局事务并返回一个唯一的 XID
- 服务A中的 RM 向 TC 注册分支事务,然后将这个分支事务纳入 XID 对应的全局事务管辖中
- 服务A开始执行分支事务
- 服务A开始远程调用B服务,此时 XID 会根据调用链传播
- 服务B中的 RM 也向 TC 注册分支事务,然后将这个分支事务纳入 XID 对应的全局事务管辖中
- 服务B开始执行分支事务
- 全局事务调用处理结束后,TM 会根据有误异常情况,向 TC 发起全局事务的提交或回滚
- TC 协调其管辖之下的所有分支事务,决定是提交还是回滚
Seata使用
我们从上面了解到了 Seata 的组成和执行流程,我们接下来就来实际的使用下 Seata。
示例演示
我们简单创建了一个微服务项目,其中有订单服务和库存服务。
我们这里采用了 nacos 作为注册中心,分别启动两个服务,我们在nacos控制台可以看到两个已经注册的服务:
号外:如果对nacos还不熟悉的小伙伴可以跳转查看 nacos讲解:微服务新秀之Nacos
我们接着创建了一个数据库,其中有两张表:c_order 和 c_product,其中商品表中有一条数据,而订单表中还未有数据,接下来我们将要对其进行操作!
我们现在模拟一个下单的过程:
- 请求进来,通过商品 pid 往数据库中查商品的信息
- 创建一条该商品的订单
- 对应扣减该商品的库存量
- 流程结束
我们接下来就进入代码演示一下:
注意:这里 ProductService 并非是库存服务里面的类,而是利用 Feign 远程调用库存服务的接口
代码三步走,正常请况下肯定是没有问题的:
订单生成,库存也对应减少,感觉自己代码可以上线进入正轨的时候,我们来模拟一下库存中的异常,库存商品数量归为 100,订单表清空:
我们继续发送下单请求,可以看到库存服务已经抛出了异常
正常来说这个时候,库存表数量不应该减少,订单表不应该插入订单数据,但是事实真的是这样的吗?我们看数据:
库存数量没减,但是订单却增加了。好了,到这里,你就已经见识到了分布式事务的灾难性危害。接下来主角登场!
Seata 安装
我们首先需要点击下载地址进行下载 Seata。
由于我们是使用 nacos 作为服务中心和配置中心,因此我们下载解压后需要做一些修改操作
- 进入 conf 目录编辑 registry.conf 和 file.conf 两个文件,编辑后内容如下:
- 由于新版 Seata 中没有 nacos-conf.sh 和 config.txt 两个文件,因此我们需要独立下载:
nacos-config.sh 下载地址
config.txt 下载地址
我们需要将 config.txt 文件放到 seata 目录下,而非 conf 目录下,并且需要修改 config.txt 内容
config.txt就是seata各种详细的配置,执行 nacos-config.sh 即可将这些配置导入到nacos,这样就不需要将file.conf和registry.conf放到我们的项目中了,需要什么配置就直接从nacos中读取。
- 执行导入
在 conf 目录下打开 git bash 窗口,执行以下命令:
sh nacos-config.sh -h localhost -p 8848 -g SEATA_GROUP -t namespace-id(需要替换) -u nacos -w nacos
复制代码
操作结束后,我们便可以在 nacos 控制台中看到配置列表,日后配置有需要修改便可以直接从这边修改,而不用修改目录文件:
- 数据库配置
在 1.4.1 最新版中依然没有 sql 文件,所以我们还是需要另外下载:sql 下载地址
在 seata 数据中执行这个文件,生成三张表:
在我们的业务数据库中执行 undo_log 这张表:
CREATE TABLE `undo_log`
(
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
`branch_id` BIGINT(20) NOT NULL,
`xid` VARCHAR(100) NOT NULL,
`context` VARCHAR(128) NOT NULL,
`rollback_info` LONGBLOB NOT NULL,
`log_status` INT(11) NOT NULL,
`log_created` DATETIME NOT NULL,
`log_modified` DATETIME NOT NULL,
`ext` VARCHAR(100) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = INNODB
AUTO_INCREMENT = 1
DEFAULT CHARSET = utf8;
复制代码
- 添加 log 文件
如果我们没有log输出文件,启动 seata 可能会报错,因此我们需要在 seata 目录下创建 logs 文件夹,在 logs 文件下创建 seata_gc.log 文件
- 启动
做好了以上准备,我们便可以启动 seata 了,直接在 bin 目录下 cmd 执行 bat 脚本即可,启动结束便可在 nacos 中看到 seata 服务:
Seata 集成
在 Seata 安装的步骤中我们便完成了 Seata 服务端 的启动安装,接下来就是在项目中集成 Seata 客户端
- 第一步:我们需要在 pom.xml 文件中添加两个依赖:seata 依赖 和 nacos 配置依赖
<!--nacos-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!--seata-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<exclusions>
<!-- 排除依赖 指定版本和服务器端一致 -->
<exclusion>
<groupId>io.seata</groupId>
<artifactId>seata-all</artifactId>
</exclusion>
<exclusion>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-all</artifactId>
<version>1.4.1</version>
</dependency>
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>1.4.1</version>
</dependency>
复制代码
注意: 这里需要排除
spring-cloud-starter-alibaba-seata 自带的 seata 依赖,然后引入我们自己需要的 seata 版本,如果版本不一致启动时可能会造成 no available server to connect 错误!
- 第二步:我们需要把 restry.conf 文件复制到项目的 resource 目录下
- 第三步:需要自己配置seata代理数据源
@Configuration
public class DataSourceProxyConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DruidDataSource druidDataSource() {
return new DruidDataSource();
}
@Primary
@Bean
public DataSourceProxy dataSource(DruidDataSource druidDataSource) {
return new DataSourceProxy(druidDataSource);
}
}
复制代码
配置完数据源我们得在启动类的 SpringBootApplication 上排除Druid数据源依赖,否则可能会出现循环依赖的错误:
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
复制代码
- 第四步:在 nacos 的配置文件控制台中加入我们服务的事务组项:
service.vgroupMapping + 服务名称 = default
group为: SEATA_GROUP
复制代码
- 第五步:项目中配置修改
- 第六步:开启全局事务
这步就是最终一步了,在我们需要开启事务的方法上添加 @GlobalTransactional 注解,类似于我们单体事务添加的@Transactional
Seata 测试
我们现在回到项目中,在上面的示例演示中,我们已经知道了如果库存服务发生异常,会出现的情况是,库存没有减少,而订单依然会生成。那我们如果增加了 Seata 来管理全局事务,情况是否会有所改变?我们测试如下:
库存服务已经了异常:
看下数据库数据:
看样子我们全局事务已经生效了,事务也已经完美的控制住了!
而我们创建的 undo_log 这张表在管理事务中也启动了重要的作用:
看完了以上操作,我们趁热打铁来梳理一下其中的执行流程,让你印象更加深刻些~
相信看完这张图,你对 Seata 执行事务的流程也更加熟悉了吧!
这还没结束,我们接着来看看其中的一些要点:
- 每个 RM 都需要使用 DataSourceProxy 连接数据库,这样是为了使用 ConnectionProxy,使用数据源和数据连接代理的目的就是在第一阶段将 undo_log 和业务数据放在一个本地事务提交,这样就保存了只要有业务操作就一定有 undo_log 产生!
- 在第一阶段的 undo_log 中存放了数据修改前和修改后的值,为事务回滚做好准备,所以第一阶段就已经将分支事务提交,也就释放了锁资源!
- TM 开启全局事务后,便会将 XID 放入全局事务的上下文中,我们通过 feign 调用也会将 XID 传入下游服务中,每个分支事务都会将自己的 Branch ID 与 XID 相关联!
- 第二阶段如果全局事务是正常提交,那么TC 会通知各分支参与者提交分支事务,各参与者只需要删除对应的 undo_log 即可,并且可以异步执行!
- 第二阶段如果全局事务需要回滚,那么 TC 会通知各分支事务参与者回滚分支事务,通过 XID 和 Branch ID 找到相应的 undo_log 日志,通过回滚日志生成反向 SQL 并执行,完成事务提交之前的状态,如果回滚失败便会重试回滚操作!
猜你喜欢
- 2025-05-03 用Arduino mega2560及Ethernet扩展板做一个web简易服务器
- 2025-05-03 不买光盘 不用下载 Stadia:游戏要云起来
- 2025-05-03 linux命令 - fuser、lsof、pidof学习
- 2025-05-03 Linux与windows共享文件的神器:samba
- 2025-05-03 SpringBoot数据校验与优雅处理详解
- 2025-05-03 用活firewalld防火墙之service(防火墙运行命令)
- 2025-05-03 深度剖析 Spring Cloud Eureka 底层实现原理
- 2025-05-03 分享一下面试被问了负载均衡的这些问题
- 2025-05-03 一分钟了解SpringCloud中的ribbon到底是什么,原理是啥?
- 2025-05-03 内存最大,最省电NAS装机:34瓦128GB内存,14盘位NAS设置教程
- 最近发表
- 标签列表
-
- location.href (44)
- document.ready (36)
- git checkout -b (34)
- 跃点数 (35)
- 阿里云镜像地址 (33)
- qt qmessagebox (36)
- md5 sha1 (32)
- mybatis plus page (35)
- semaphore 使用详解 (32)
- update from 语句 (32)
- vue @scroll (38)
- 堆栈区别 (33)
- 在线子域名爆破 (32)
- 什么是容器 (33)
- sha1 md5 (33)
- navicat导出数据 (34)
- 阿里云acp考试 (33)
- 阿里云 nacos (34)
- redhat官网下载镜像 (36)
- srs服务器 (33)
- pico开发者 (33)
- https的端口号 (34)
- vscode更改主题 (35)
- 阿里云资源池 (34)
- os.path.join (33)