了解更多SpringCloudAlibaba系列:深入了解构建分布式微服务架构的利器:Spring Cloud Alibaba-CSDN博客
介绍
seata官网:https://seata.io/zh-cn/
官网:Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。
在单体应用架构中,当业务方法需要执行一组sql时,需要保证数据的一致性也就是所谓的ACID数据库四大范式,此时需要@Transaction来开启事务,但是@Transaction注解只能保证本地服务的事务,而在分布式架构中,服务与服务之间进行数据调用是避免不了的,但是由于@Transaction只能维持当前服务的的事务,而不能维持当前服务之外的事务,所以当需要回滚或提交多个服务的事务时,只有本地的事务会提交或回滚,导致其他服务的数据出现错误。所以在分布式先架构中,需要使用Seata解决分布式的应用场景;
AT模式原理详解
在学习seata之前先安装seata,为了方便展示安装步骤放在了文章末尾,请先进行安装在学习;
在上面提到Seata 提供了 AT、TCC、SAGA 和 XA 事务模式,在这四种模式中功能最强大的当属AT模式,该模式实现全局事务,对代码是无侵入实现的,这也是成为官网和企业开发中主推的原因,所以在这只介绍AT模式,先了解一下模式中的几个重要角色;
模式角色:
官网:
Transaction Coordinator(TC)
事务协调器,维护全局事务的运行状态,负责协调并驱动全局事务的提交或回滚。
Transaction Manager(TM)
控制全局事务的边界,负责开启一个全局事务,并最终发起全局提交或全局回滚的决议,TM定义全局事务的边界。
Resource Manager(RM)
控制分支事务,负责分支注册、状态汇报,并接收事务协调器的指令,驱动分支(本地)事务的提交和回滚。RM负责定义分支事务的边界和行为。
事务协调器TC:也就是seata服务,负责维持全局事务,也成为事务的协调者;
事务发起者TM:负责开启一个全局事务,并最终发起全局提交或全局回滚的决议,也就是通过seata的注解@GloubTransactional标识需要开启事务的业务方法;
分支事务RM:被seata的注解所表示的方法中,所有需要参与事务的服务,也称为事务的参与者;
模式原理:
- 当请求执行到@GloubTransactional注解标识的方法时,TM事务发起者会告诉TC事务协调者开启一个全局事务,需要注意的是TM只是事务的发起者不是事务的开启者;
- TC事务协调者收到TM事务发起者要求开启一个全局事务后会开启全局事务,并向全局事务gloub_table表中生成一条数据,该数据记录了全局事务信息(如 XID、事务状态等)xid字段作为全局事务的标识,然后将xid字段返回给事务的发起者TM;
- TM收到xid之后进行服务调用,并将xid传递给事务的参与者RM;
- 当事务参与者RM收到xid之后开始,开始执行sql并处理sql(处理sql的原理参考RM实现细节),将sql处理信息记录在分支事务表undo_log中,目的是为了在需要回滚事务时进行逆向操作;信息;
- 随后RM带着xid上报TC,TC收到后创建分支事务,并在branch_table表中记录分支事务的
- 当分支事务处理完sql之后到达TM事务边界,如果分支事务执行过程没有异常,TM会想TC提交xid,如果有异常TM带着xid向TC发起全局事务回滚;
- TC接收到TM的提交请求后通知分支事务RM删除undo_log日志,同时TC删除全局事务或分支事务,如果TC收到TM的是回滚请求,将通知分支事务RM根据undo_log日志记录进行数据逆向还原并删除undo_log记录,TC同时删除全局事务及分支事务;
图片来源于网络
RM实现细节:
- 生成sql分析器对服务调用方法中的sql进行拆解;
- 根据分析得到的条件,把操作前的数据作为源数据查出来,放入到查询前置快照beforeImage中,便于回滚操作逆向恢复数据;
- 执行sql;
- sql执行之后,把操作后的数据在查询出来,放入查询后置快照aftreImage中,然后写入到undo_log表中,然后进行分支事务注册,并上报全局事务生成全局事务锁;
- 当分支事务的undo_log记录完成之后提交分支事务,并向TC事务协调者进行汇报分支事务;
图片来源于网络
使用教程
1、在需要使用全局事务的服务中添加依赖
<!--seata依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
2、在application配置文件中配置seata相关配置
第一部分
spring:
thymeleaf:
cache: true
datasource:
url: jdbc:mysql://192.168.231.131:3306/order-seata?serverTimezone=Asia/Shanghai&characterEncoding=UTF-8
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 123456
application:
name: alibaba-order-server
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
username: nacos
password: nacos
# 添加 seata的分组
alibaba:
seata:
tx-service-group: xigai
# seata配置:spring.cloud.alibaba.seata.tx-service-group=自己在配置中设置的分钟
第二部分
seata:
registry: # 配置seata的注册中心
type: nacos
nacos:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
application: seata-server
username: ${spring.cloud.nacos.discovery.username}
password: ${spring.cloud.nacos.discovery.username}
group: SEATA_GROUP
config: # seata 配置中心,读取seata在nacos中的seata client配置
type: nacos
nacos:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
username: ${spring.cloud.nacos.discovery.username}
password: ${spring.cloud.nacos.discovery.username}
group: SEATA_GROUP
3、在需要开启全局事务的业务方法上添加注解@GlobalTransactional
@GlobalTransactional
@Override
public OrderInfo orderAdd(OrderInfo orderInfo) {
try {
final int orderCont = orderInfoMapper.insert(orderInfo);
orderInfo.setOrderMsg("新增订单:"+orderCont);
System.out.println("新增订单:"+orderCont);
TimeUnit.SECONDS.sleep(5);
// 扣减库存
String isReduce = feignStockService.reduce(Integer.valueOf(orderInfo.getStockId()));
System.out.println(isReduce);
} catch (InterruptedException e) {
e.printStackTrace();
}
// int a=1/0;
return orderInfo;
}
4、服务调用参考feign组件的调用服务:feign组件调用远程服务-CSDN博客
安装步骤
1、进入下载地址下载对应版本:https://github.com/seata/seata/releases
2、下载好之后进入seata的conf目录打开file.conf配置文件修改信息存储方式,seata作为服务协调者TC有多种信息存储方式,我选择用db数据库的方式进行存储,选择数据存储的方式需要先把数据库和表提前创建好,下载路径在下面;
3、下载数据库需要的表,建议把整个工程下载下来,地址:https://github.com/seata/seata/
4、集成nacos实现配置管理,修改seata目录下的conf文件中的 registry.conf 文件
5、修改刚才下载工程的配置文件数据源,script文件夹可以单独提出来放在seata的目录下和conf等文件夹同级,但是文件路径包括父级文件路径都不能存在空格,我的seata的父级文件夹存在空格,所以我直接放在d盘下面了,这个对路径位置存放没有要求,只对文件路径是否包含空格有要求
5、执行脚本把配置文件注册到nacos配置中心
成功出来就安装完成了