目录
一、分布式事务问题:

这张图我们可以看到微服务的一个运作,现在假设创建订单、清理购物车这两个步骤没有出现问题,而扣减库存接口报错;由于交易服务调用了库存服务中的方法,因此扣减库存时报错会通知到交易服务,创建订单的事务就会被回滚,也就是1、3回滚;但是购物车服务是被交易服务调用的,购物车服务与库存服务之间并没有直接关系,这就会导致购物车服务的清理购物车事务没有得到回滚而是直接提交;这就会导致数据的不一致性,从业务上看就是提交订单失败但是购物车被清理了;所以就需要引入全局事务来解决该问题
二、Seata:
其实分布式事务产生的一个重要原因,就是参与事务的多个分支事务互相无感知,不知道彼此的执行状态。因此解决分布式事务的思想非常简单:
就是找一个统一的事务协调者,与多个分支事务通信,检测每个分支事务的执行状态,保证全局事务下的每一个分支事务同时成功或失败即可。大多数的分布式事务框架都是基于这个理论来实现的。
Seata也不例外,在Seata的事务管理中有三个重要的角色:
-
TC (Transaction Coordinator) - **事务协调者:**维护全局和分支事务的状态,协调全局事务提交或回滚。
-
TM (Transaction Manager) - **事务管理器:**定义全局事务的范围、开始全局事务、提交或回滚全局事务。
-
RM (Resource Manager) - **资源管理器:**管理分支事务,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。

其中,TM 和RM 可以理解为Seata的客户端部分,引入到参与事务的微服务依赖中即可。将来TM 和RM 就会协助微服务,实现本地分支事务与TC之间交互,实现事务的提交或回滚。
而TC服务则是事务协调中心,是一个独立的微服务,需要单独部署。
那么我们就来部署一下TC服务:
TC部署:
1.Seata支持多种存储模式,但考虑到持久化的需要,我们一般选择基于数据库存储。执行课前资料提供的《seata-tc.sql》
,导入数据库表:

2.将整个seata文件夹、以及seata的tar包拷贝到虚拟机的/root
目录:

3.加载seata的tar包并创建镜像:

4.确保nacos、mysql都在hm-net网络中并在虚拟机的/root
目录执行下面的命令:
通过以下指令查看是否在网络当中:
bash
docker network ls #用于查看所有网络,这里应该要有hm-net
docker inspect mysql #可以查看mysql容器的网络状况,里面应该要有hm-net
docker inspect nacos #可以查看nacos容器的网络状况,里面应该要有hm-net



这里发现nacos的网络没配置好,我们输入以下指令:
bash
docker network connect hm-net nacos
再次执行docker inspect nacos查看:

接下来就可以执行容器的创建指令了:
bash
docker run --name seata \
-p 8099:8099 \
-p 7099:7099 \
-e SEATA_IP=192.168.150.101 \
-v ./seata:/seata-server/resources \
--privileged=true \
--network hm-net \
-d \
seataio/seata-server:1.5.2

到网页中访问192.168.150.101:7099试试:

微服务集成Seata:
由于购物车、商品、交易模块要用到Seata,所有我们现在改造这三个模块的代码:
1.引入依赖:
XML
<!--统一配置管理-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!--读取bootstrap文件-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<!--seata-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
2.在nacos上添加一个共享的seata配置,命名为shared-seata.yaml
:
TypeScript
seata:
registry: # TC服务注册中心的配置,微服务根据这些信息去注册中心获取tc服务地址
type: nacos # 注册中心类型 nacos
nacos:
server-addr: 192.168.150.101:8848 # nacos地址
namespace: "" # namespace,默认为空
group: DEFAULT_GROUP # 分组,默认是DEFAULT_GROUP
application: seata-server # seata服务名称
username: nacos
password: nacos
tx-service-group: hmall # 事务组名称
service:
vgroup-mapping: # 事务组与tc集群的映射关系
hmall: "default"
3.给三个模块添加或修改bootstrap.yaml
:
TypeScript
spring:
application:
name: *****-service # 服务名称
profiles:
active: dev
cloud:
nacos:
server-addr: 192.168.150.101:8848 # nacos地址
config:
file-extension: yaml # 文件后缀名
shared-configs: # 共享配置
- dataId: shared-jdbc.yaml # 共享mybatis配置
- dataId: shared-log.yaml # 共享日志配置
- dataId: shared-swagger.yaml # 共享日志配置
- dataId: shared-seata.yaml # 共享seata配置
4.修改原先的application.yaml文件:
TypeScript
server:
port: ****
feign:
okhttp:
enabled: true # 开启OKHttp连接池支持
sentinel:
enabled: true # 开启Feign对Sentinel的整合
hm:
swagger:
title: **服务接口文档
package: com.hmall.*****.controller
db:
database: hm-*****
分布式事务-XA模式:


接下来我们就来实现XA模式:
1.在配置文件中指定要采用的分布式事务模式。我们可以在Nacos中的共享shared-seata.yaml配置文件中设置:

2.在事务的起点方法上添加@GlobalTransactional
注解,将来TM就会基于这个方法判断全局事务范围,初始化全局事务。

以及涉及到的两个方法上添加@Transactional注解


分布式事务-AT模式:


具体实现:
1.在遭遇分布式事务问题的模块下创建快照表存储快照信息:

2.到nacos当中修改shared-seata.yaml:
