前语

项目中需求A服务调用B服务,当A服务办法体内呈现反常时,若B服务办法已履行,要求B服务能够进行回滚,需求借助分布式业务实现。Seata是一个比较老练的分布式业务东西,但官方文档比较简练,查阅网上资料也版别较多不太一致,在此记载一下集成进程以供下次参阅。

环境信息

操作系统:Windows10
JDK:1.8.0_351
SpringCloud版别:2021.0.3
Seata版别:1.7.0

集成进程

一、布置发动seata-server

1. 下载seata-server

从Github上下载所需版别的seata-server-x.x.x.zip(我这里是1.7.0)后在本机解压。解压后理论上直接运转bin目录下的bat脚本就可以运转seata服务,linux环境下则是运转sh脚本。但实践项目中肯定要结合数据库和Nacos运用,所以需求修正装备文件。

2. 修正装备文件

需求留意的是,1.5.0之前的版别装备文件是有多个的,都坐落conf文件夹下,如file.conf,registry,conf等。在1.5.0版别之后都整合到一个装备文件里了,即application.yml。以下装备项请依照自己版别查找修正。

以seata-1.7.0为例,翻开conf/application.yml进行修正,要点修正nacos部分装备。

server:
  port: 7091
spring:
  application:
    name: seata-server
logging:
  config: classpath:logback-spring.xml
  file:
    path: ${user.home}/logs/seata
  extend:
    logstash-appender:
      destination: 127.0.0.1:4560
    kafka-appender:
      bootstrap-servers: 127.0.0.1:9092
      topic: logback_to_logstash
console:
  user:
    username: seata
    password: seata
seata:
  # nacos装备
  config:
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848
      namespace:
      group: SEATA_GROUP
      username:
      password:
      context-path:
      data-id: seataServer.properties
      ##if use MSE Nacos with auth, mutex with username/password attribute
      #access-key:
      #secret-key:
  registry:
    # nacos装备
    type: nacos
    nacos:
      application: seata-server
      server-addr: 127.0.0.1:8848
      group: SEATA_GROUP
      namespace:
      cluster: default
      username:
      password:
      context-path:
      ##if use MSE Nacos with auth, mutex with username/password attribute
      #access-key:
      #secret-key:
#  server:
#    service-port: 8091 #If not configured, the default is '${server.port} + 1000'
  security:
    secretKey: SeataSecretKey0c382ef121d778043159209298fd40bf3850a017
    tokenValidityInMilliseconds: 1800000
    ignore:
      urls: /,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.jpeg,/**/*.ico,/api/v1/auth/login

修正成功后,意味着seata将从nacos获取装备信息,同时注册本身服务到nacos中心。

3. nacos准备

留意到上面装备项中有一项:seata.config.data-id=seataServer.properties,意思为要读nacos上的seataServer.properties装备文件,接下来去Nacos创立该装备文件,留意Group与第2步中的保持一致,这里是SEATA_GROUP

SpringCloud+Nacos集成Seata-1.7.0分布式事务

详细装备项是从seata-server-1.7.0/seata/script/config-center/config.txt粘贴修正而来,其他博客一般建议全粘,笔者查找源码发现那些通用装备项代码里现已写好默许值了,假如不修正没必要都粘过来,这里只运用对咱们有用的装备,主要是数据库装备信息。

#Transaction storage configuration, only for the server.
store.mode=db
store.lock.mode=db
store.session.mode=db
#These configurations are required if the `store mode` is `db`.
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.cj.jdbc.Driver
store.db.url=jdbc:mysql://x.x.x.x:3306/ccxi_seata?useSSL=false&useUnicode=true&rewriteBatchedStatements=true
store.db.user=root
store.db.password=password@1234$#11
store.db.minConn=5
store.db.maxConn=30
store.db.globalTable=global_table
store.db.branchTable=branch_table
store.db.distributedLockTable=distributed_lock
store.db.queryLimit=100
store.db.lockTable=lock_table
store.db.maxWait=5000

留意数据库衔接串和驱动类型必定要写对,假如是Mysql8要运用com.mysql.cj.jdbc.Driver。可参阅自己Java项目中的装备进行填写。

4. 数据库建表

在上面装备的数据库内,履行seata-server-1.7.0/seata/script/server/db目录下的sql脚本(依据数据库类型),创立服务端所需的表。

5. 发动seata-server

server端根底装备现已完结,运转bin下的bat脚本发动服务(linux运用sh脚本)。呈现下述打印即为发动成功。

SpringCloud+Nacos集成Seata-1.7.0分布式事务

发动成功后,可登录http://ip:7091/#/login 进入seata办理页面,默许用户名和暗码都为seata

SpringCloud+Nacos集成Seata-1.7.0分布式事务

二、微服务(客户端)集成

1. 增加pom依靠

server现已发动,接下来要把需求运用分布式业务的微服务都注册到server上去。首先在每个微服务内增加pom依靠。其间seata-spring-boot-starter这个包为seata核心包,版别号要与自己上述服务端保持一致。此外假如运用SpringCloudspring-cloud-starter-alibaba-seata也必不可少,这个包的版别号最好与所运用SpringCloud版别保持一致。

<dependencies>
    ...
    <!-- Seata-->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
        <version>${alibaba.cloud.version}</version>
        <exclusions>
            <exclusion>
                <groupId>io.seata</groupId>
                <artifactId>seata-spring-boot-starter</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>io.seata</groupId>
        <artifactId>seata-spring-boot-starter</artifactId>
        <version>1.7.0</version>
    </dependency>
    ...
</dependencies>

2. 客户端增加seata装备

包引入后,需求在微服务yml里增加seata客户端所需的装备:

#seata客户端装备
seata:
  enabled: true
  application-id: ccxi-abc
  tx-service-group: ccxi_tx_group
  service:
    vgroup-mapping:
      ccxi_tx_group: default
  registry:
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848
      namespace: public
      group: SEATA_GROUP
      application: seata-server

其间tx-service-group为咱们自定义的业务组,姓名随便起,可是下面service.vgroup-mapping下必定要有一个对应你这个姓名的映射,映射到default(seata默许的集群称号)。 nacos方面,咱们仅装备注册项,即registry下的装备,装备内容与服务端保持一致。这里只装备registry信息而不再装备config相关信息,是因为一是作为客户端,没有必要再到nacos读取装备,原本也没多少装备项,且不需求频频更换。二是假如运用nacos装备,则需求在nacos上再装备tx-service-group等信息,费力不讨好,且容易与原本的微服务装备构成混淆。

3. 创立undo_log表(仅AT形式)

seata中默许运用的是AT形式,该形式需求每个客户端库内都存在一张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;

4. 发动客户端

装备完结后,照常发动微服务,假如没有反常,在服务端和客户端分别能看到打印,证明客户端成功注册到了服务端。

SpringCloud+Nacos集成Seata-1.7.0分布式事务

SpringCloud+Nacos集成Seata-1.7.0分布式事务

5. 测验及运用

在所需求运用分布式业务的办法上增加注解@GlobalTransactional,当办法内发生反常时,就可以带动所调用微服务进行回滚。

@Override
@GlobalTransactional(rollbackFor = Exception.class)
public void approve(Long id, String taskKey, String comment) throws Exception {
   Ticket ticket = getTicket(id);
   // 调用流程微服务进行批阅操作
   processClient.approve(ticket, taskKey, comment, null);
   // 修正本地工单状态
   ticket.setState(TicketState.APPROVED);
   ticketService.saveOrUpdate(ticket);
   // 记载操作日志
   processLogger.log(ticket.getBusinessKey(), "批阅经过", null);
   // 抛出反常测验分布式业务
   throw new Exception("呈现反常:测验分布式业务");
}

假如成功触发回滚,两个微服务的控制台均会打印相关信息,要点重视xid应该为一致的。

服务A日志

SpringCloud+Nacos集成Seata-1.7.0分布式事务

服务B日志

SpringCloud+Nacos集成Seata-1.7.0分布式事务

弥补

依照上面步骤集成完之后假如发现不能正常回滚,应在每个服务的办法内打印下xid,看看是否一致,有没有xid为空的。假如有服务拿不到xid,查看下微服务调用时是否拦截掉了这部分header信息。

System.out.println(RootContext.getXID());

【坑】别的,windows下运用时,服务端经常会自己卡住,需求手动到bat窗口内敲回车来免除卡顿。