SpringCloudAlibaba之Seata分布式事务

一、什么是Seata?

  Seata是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata将为用户提供了AT、TCC、SAGA 和XA事务模式,为用户打造一站式的分布式解决方案。

  微服务中通常一次大的操作由不同的小操作组成的,这些小的操作分布在不同的服务器上,我们需要一定的方案来保证这些小操作要么全部成功,要么全部失败。从本质上来说,就是为了保证不同数据库的数据一致性。分布式事务就是一个保证数据一致性的解决方案。

  Seata分布式事务的处理包含全局唯一事务ID和三个组件模块TC\TM\RM:

    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会将第一阶段保存的快照数据和行锁删除清空数据即可,反之则根据快照恢复全部数据到之前的状态(在还原数据之前会校验脏写,检查是否已被其他操作处理过,如果是则需要人工介入),然后再删除快照和行锁数据。流程如下:

 

 

posted @ 2021-10-18 14:08  我若安好,便是晴天  阅读(289)  评论(0编辑  收藏  举报