一、什么是Seata?
Seata是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata将为用户提供了AT、TCC、SAGA 和XA事务模式,为用户打造一站式的分布式解决方案。
微服务中通常一次大的操作由不同的小操作组成的,这些小的操作分布在不同的服务器上,我们需要一定的方案来保证这些小操作要么全部成功,要么全部失败。从本质上来说,就是为了保证不同数据库的数据一致性。分布式事务就是一个保证数据一致性的解决方案。
Seata分布式事务的处理包含全局唯一事务ID和三个组件模块TCTMRM:
TC事务协调器:维护全局事务的运行状态,负责协调并驱动全局事务的提交或回滚。
TM事务管理器:控制全局事务的边界,负责开启一个全局事务,并最终发起全局提交或全局回滚的决议。
RM资源管理器:控制分支事务,负责分支注册,状态汇报,并接收事务协调器的指令,驱动分支事务的提交和回滚。
以下是分布式事务的处理过程:
1. TM向TC申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的XID。
2. XID在微服务调用链路的上下文中传播。
3. RM向TC注册分支事务,将其纳入XID对应全局事务的管辖。
4.TM向TC发起针对XID的全局提交或回滚决议。
5.TC调度XID下管辖的全部分支事务完成提交或回滚请求。
二、Seata的使用
1、下载安装:去http://seata.io/zh-cn下载对应版本,解压到指定目录并修改conf目录下的file.conf配置文件。主要配置自定义事务组的名称,事务日志的存储模式为db和数据库连接信息。
a. 修改自定义事务组名称:service.vgroup_mapping.my_test_tx_grou= "zqh_tx_group" 。
b.修改事务日志的存储模式:store.mode="db"。
c.创建数据库,复制conf/db_store.sql代码去库下执行创建表。
d.配置数据连接:db.*下配置。
e.修改conf/registry.conf文件:设置registry.type="nacos", nacos{ serverAddr="localhost:8848",namsespace="" ,cluster=“default”},将Seata-server服务注册到nacos注册中心。
f.启动:先启动nacos、后启动seata(运行bin/seata-server.bat)。
2、创建微服务对应的业务数据库:每个微服务需要对应一个数据库,为每个微服务的数据库创建各自的回滚日志表:复制conf/db_undo_log.sql在每个库中执行一次。
3、创建微服务(Controller-domain-Dao-Service-mapping代码结构):
a.引入seata包,要注意排除jar包冲突:
<! --seata-->
<dependency>
<grouprd>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<exclusions>
<exclusion>
<artifactid>seata-all</artifactId>
<groupid>io.seata</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupid>io.seata</grouprd>
<artifactId>seata-all</artifactId>
<version>0.9.0</version>
</dependency>
b.配置yml文件,指定事务组名称:
server: port: 2001 spring: application: name: seata-order-service cloud: alibaba: seata: #自定义事务组名称需要与seata-server中的对应 tx-service-group: zqh_tx_group nacos: discovery: server-addr: localhost:8848 datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc :mysql:/ /localhost:3306/ seata_order username: root password: 123456
c.复制file.conf、registry.conf到微服务resources资源文件夹。
d.主启动类增加@SpringBootApplication(exclude = DatasourceAutoconfiguration.class)注解取消数据源的自动创建,选择使用自定义的Seata数据源DataSourceProxyConfig类进行代理。
e.在调用微服务的接口服务类上增加@GlobalTransactional注解,完成微服务的一些列调用过程中的事务处理,当调用微服务过程中出现rollbackFor指定的异常,就会全局回滚create()里的任何调用,例如
/*创建订单->调用库存服务扣减库存->调用账户服务扣减账户余额->修改订单状态*简单说:下订单->扣库存->减余额->改状态*/ @override @GlobalTransactional(name = "zqh-create-order" ,rollbackFor = Exception.class) //rollbackFor表示导致事务回滚的异常类数组,name表示事务的名称,具有唯一性 public void create(order order) { Log.info("----->开始新建订单"); orderDao.create(order); Log.info("----->订单微服务开始调用库存,做扣减count" ); storageservice.decrease(order.getProductId() ,order.getcount()); Log.info("----->订单微服务开始调用账户,做扣减Money" ) ; accountservice.decrease(order.getuserId( ) ,order.getMoney()); Log.info("----->订单微服务开始修改订单状态"); orderDao.update(order-getuserId(), status: 1); Log.info( "----->修改订单状态结束"); Log.info("----->下订单结束了,o(n_n)o哈哈~"); }
三、Seata原理简介
Seata是2019年蚂蚁金服和阿里巴巴共同开源的分布式事务解决方案,商用的时候要使用1.0以上,0.9版本不支持大规模集群。在前面我们完成了简单的微服务事务方案,其中增加了@GlobalTransactional注解的微服务就是TM,Seata服务器就是TC,事务的参与方就是RM。
在运行第一阶段,Seata会拦截业务sql语句,解析sql语义,在数据操作前保存之前的"before image"镜像,执行操作后保存"after image"镜像,最后生成行锁,这些操作全部在一个事务中完成。流程如下:
第二阶段,如果提交顺利,Seata会将第一阶段保存的快照数据和行锁删除清空数据即可,反之则根据快照恢复全部数据到之前的状态(在还原数据之前会校验脏写,检查是否已被其他操作处理过,如果是则需要人工介入),然后再删除快照和行锁数据。流程如下: