5.SpringCloud:Seata分布式事务

目录

一、Seata介绍

Seata基本概念

更多原理和过程分析

二、无分布式事务控制的情况

三、Seata概念

事务分组概念释疑

 五、Seata服务端安装配置

 六、Seata客户端(AT模式)

 七、Seata服务端调整配置

附录A:Seata需要的SQL等官方脚本


一、Seata介绍

seata全称是:simple extensiable autonomous transaction architecture,中文直译就是:简单的、可扩展的、自治的事务架构。 

Seata作为跨数据库的分布式事务管理和解决办法,提供了AT、TCC、Saga、XA四种事务模式解决方案。 其中AT模式对业务代码几乎零修改零侵入。相关介绍请见官网。

  Seata分为服务端(Seata Server)和客户端(即各个微服务)。服务端即TC全局协调中心,客户端即TM和RM。

 Seata基本概念

在 Seata 的架构中,一共有三个角色:

  • TC (Transaction Coordinator) - 事务协调者:维护全局和分支事务的状态,驱动全局事务提交或回滚。 (个人感觉若叫“Global Transaction Coordinator”  GTC更加直观)
  • TM (Transaction Manager) - 事务管理器:定义全局事务的范围,开始全局事务、提交或回滚全局事务。
  • RM ( Resource Manager ) - 资源管理器:管理分支事务处理的资源( Resource ),与 TC 交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。

 其中,TC 为单独部署的Seata-Server 服务端,TM 和 RM 为嵌入到各个微服务应用中的 Client 客户端。

在 Seata 中,分布式事务的生命周期示意图如下(绿色箭头为服务间调用链路,传递过程中自动携带全局事务xid的传递):

注:全局事务的整体提交还是回滚,是由全局事务的发起方来决定的。 发起方决定后,告诉TC,并由TC通知各服务进行branch事务在各服务本地的commit/rollback操作。

 更多原理和过程分析

可参见文章:[图文] Seata AT 模式分布式事务源码分析_旧时光 | YoungChen's 博客-CSDN博客

二、无分布式事务控制的情况

   在之前的Java工程(4.SpringCloud:Sentinel服务流控与服务降级_zyplanke的专栏-CSDN博客)已经有支付服务、订单服务。在其工程基础上,对其进行修改(主要是增加对数据库的访问)

 1、对pom.xml增加spring-boot-starter-data-jpa、mysql-connector-java、druid-spring-boot-starter三个依赖。内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.11</version>
        <relativePath/>
    </parent>

    <modules>
        <module>payment</module>
        <module>order</module>
    </modules>

    <groupId>com.example</groupId>
    <artifactId>myproject-global-pom</artifactId>
    <version>0.0.1-DEFAULT</version>
    <packaging>pom</packaging>
    <description>This is my project global pom config</description>
    <properties>
        <java.version>1.8</java.version>
        <springcloud.version>3.0.4</springcloud.version>
        <springcloudalibaba.version>2021.1</springcloudalibaba.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <version>${springcloudalibaba.version}</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
            <version>${springcloudalibaba.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
            <version>${springcloud.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
            <version>${springcloud.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
            <version>${springcloud.version}</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
            <version>${springcloudalibaba.version}</version>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
            <version>1.8.0</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.22</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.8</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

 2、支付服务:定义支付服务数据库表InnoDB engine(并插入一条数据)

mysql> create schema payment;
mysql>  create table payment.T_PAY(order_id int, amount int, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY `PK_T_PAY` (order_id) ) ENGINE = InnoDB;
Query OK, 0 rows affected (0.02 sec)

mysql> desc payment.T_PAY;
+-------------+----------+------+-----+-------------------+-------------------+
| Field       | Type     | Null | Key | Default           | Extra             |
+-------------+----------+------+-----+-------------------+-------------------+
| order_id    | int      | YES  |     | NULL              |                   |
| amount      | int      | YES  |     | NULL              |                   |
| create_time | datetime | YES  |     | CURRENT_TIMESTAMP | DEFAULT_GENERATED |
+-------------+----------+------+-----+-------------------+-------------------+
3 rows in set (0.00 sec)

  3、支付服务:修改支付服务的PaymentController.java,内容如下 (增加数据库SQL,URL参数改为userid )

@RestController
public class PaymentController {
    @Value("${server.port}")
    private int myport;

    @Autowired
    private JdbcTemplate jdbcTemplate;

    Logger logger = LoggerFactory.getLogger(PaymentController.class);

    @GetMapping("/dopay/{orderid}")
    public ResponseEntity<String> paylogic(@PathVariable("orderid") Long orderid) {
        int insert_rows = jdbcTemplate.update("insert into T_PAY (order_id, amount) values (" + orderid +", 999)");
        logger.info("支付服务successful! orderid=" + orderid + ", 支付成功。 支付服务的端口为port=" + myport);
        return ResponseEntity.ok("支付服务successful! orderid=" + orderid + ", 支付成功。 支付服务的端口为port=" + myport);
    }
}

 4、支付服务:由于该服务使用Nacos作为配置中心,因此在Nacos中 修改Data ID=paymentService.properties的配置,增加数据库连接信息配置如下:

5、订单服务:定义订单服务数据库表(InnoDB engine)

mysql> create schema orders;
mysql> create table orders.T_Order (order_id int, address varchar(128), remark varchar(256), create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY `PK_T_Order` (order_id) ) ENGINE = InnoDB ;
Query OK, 0 rows affected (0.02 sec)

mysql> desc orders.T_Order;
+-------------+--------------+------+-----+-------------------+-------------------+
| Field       | Type         | Null | Key | Default           | Extra             |
+-------------+--------------+------+-----+-------------------+-------------------+
| order_id    | int          | YES  |     | NULL              |                   |
| address     | varchar(128) | YES  |     | NULL              |                   |
| remark      | varchar(256) | YES  |     | NULL              |                   |
| create_time | datetime     | YES  |     | CURRENT_TIMESTAMP | DEFAULT_GENERATED |
+-------------+--------------+------+-----+-------------------+-------------------+
4 rows in set (0.00 sec)

  6、订单服务:修改订单服务的OrderController.java。先调用支付服务,然后模拟异常。内容如下 

@RestController
public class OrderController {

    @Autowired
    private IPaymentServiceClient paymentServiceClient;

    @Autowired
    private JdbcTemplate jdbcTemplate;

    Logger logger = LoggerFactory.getLogger(OrderController.class);
    boolean forcefail = true;

    @GetMapping("/consumer/{orderid}")
    public ResponseEntity<String> consumerFeign(@PathVariable("orderid") Long orderid) {
        String result = paymentServiceClient.dodopay(orderid).getBody(); // 调用支付服务进行支付
        logger.info("[paymentService result]: {}", result);

        jdbcTemplate.update("insert T_Order(order_id, address, remark) values (" + orderid + ", 'dizhi', '"+result+"')");

        //模拟在支付完成后,本订单事务后续处理过程中发生异常后,全局回滚功能
        if (forcefail) {
            throw new RuntimeException("模拟在支付完成后,本订单事务后续处理过程中发生异常!");
        }

        return ResponseEntity.ok ("调用订单服务完成。 订单orderid:" + orderid + ",   调用支付返回的Body:" + result);
    }
}

  6、订单服务:由于该服务使用Nacos作为配置中心,因此在Nacos中 修改Data ID=orderService.properties的配置,增加数据库连接信息配置如下

 7、测试。curl  http://localhost:8888/consumer/66

 8、结论:先支付后订单入库的流程中,在支付完成后,本订单事务后续处理过程中发生异常,本应该整体回归。然而实际上支付表中的记录仍然存在,并未整体回滚,未能实现跨库事务一致性。

因此需要借用Seata等分布式事务组件来解决此类问题。

三、Seata概念

请先阅读官网文档(必读知识包括):

事务分组概念释疑

其中事务分组及相关的几个概念参数,网上大多文章有误导。正确的理解为:

tx-service-group事务分组

事务分组是seata的资源逻辑概念。

即可以按微服务的需要对事务进行逻辑上分组,每组取一个名字

在客户端(微服务)配置。

在Spring的配置参数形式如下:

seata.tx-service-group=mytest-tx-group

或者用spring.cloud.alibaba.seata.tx-service-group配置

如以上不指定,则逻辑事务分组名默认规则为:spring.application.name值+"-seata-service-group"

vgroup-mapping

即seata-server服务端节点组成的集群cluster名。

需要在客户端(微服务)中,对每个逻辑事务分组指定映射使用的vgroup-mapping(即服务端的cluster)。

通过此映射关系调整,即可切换到不同服务端cluster。

在客户端(微服务)配置。

指定逻辑事务分组映射到vgroup-mapping(vgroup-mapping的值需要与seata-server中registry.conf中的cluster保持一致)。

在Spring的配置参数形式如下:

seata.service.vgroup-mapping.mytest-tx-group=beijing

其中:红色为事务分组名

等号右侧值无需引号;且与seata-server的cluster名相同

grouplist

与上面不是同级别概念。

它的用途是:直接在客户端对vgroup-mapping(即服务端cluster)配置各个seata-server服务端节点IP和端口信息。

在客户端(微服务)配置。

推荐使用seata.registry.type=nacos或其他类型(微服务客户端和seata-server服务端应同时指定为nacos),因为使用Nacos,客户端通过Nacos即可自动获得seata-server服务端节点的IP和端口信息。

如果不是nacos等注册中心,则需要在客户端(微服务)配置中,通过以下两个参数直接指定seata-server服务端节点信息:

在Spring的配置参数形式如下(官方不推荐):

seata.registry.type=file

seata.service.grouplist.beijing=seata-serverIP:Port

其中:紫色为vgroup-mapping名(即seata-server的cluster名)

网上文章常见的错误为:

  1. 网上这几个概念分不清楚(其实主要怪Seata官网文档写得不好,网上很多文章不假思索的抄袭而导致的);
  2. 网上错误理解为上面三个参数还需要在seata-server服务端配置。实际上这些参数都是在客户端配置,不是服务端的配置;
  3. 网上错误要求把registry.conf与file.conf文件需要拷贝到客户端(微服务)的resources目录下,对于SpringBoot应用其实完全不需要。
  4. 其他:官网的文档、范例与最新的seata版本不一致,文档与文档之间存在矛盾。(例如上面的"-seata-service-group",官网文档截止到2021年12月中旬<事务分组>章节中仍然错写为"-fescar-service-group"),没办法,被迫提了个PR以修正官方文档中的一些问题,于2021年12月下旬并入官方文档并已经对外发布,避免继续误导大家。


四、环境介绍

  • Seata服务端seata-server:部署Seata Server及Seata需要管理事务专用的数据库MySQL
  • Seata客户端:即各个微服务。即在本例中包括:支付服务和订单服务。

 五、Seata服务端安装配置

1、下载并解压seata-server

wget https://github.com/seata/seata/releases/download/v1.4.2/seata-server-1.4.2.zip
unzip seata-server-1.4.2.zip

解压后,目录结果为:

├──bin
├──conf
├──log
└──lib

2、配置seata-server。Seata服务端的conf目录可以看到配置文件:

  • registry.conf该文件必须存在。定义seata-server所需要的:registry注册中心和config配置中心。其中:
    • registry.type注册中心类型可选范围为:file 、nacos 、eureka、redis、zk、consul、etcd3、sofa。 通常选择nacos配置中心作为注册中心。
    • config.type配置中心类型可选择范围为:file、nacos 、apollo、zk、consul、etcd3。
  • file.conf:仅在服务端registry.conf文件中选择配置registry.type=file或config.type=file时,才需要此file.conf文件(可在此文件中指定分布式事务管理的存储模式store.mode)
  • 无论是file、还是nacos,还是其他作为配置来源。都需要定义分布式事务管理的存储模式store.mode。存储模式有三种:file、db、redis。
    • 若选择为store.mode=file,Seata的事务相关信息会存储在内存中,并持久化到本地root.data文件中。性能比较高。 
    • 若选择为store.mode=db。Seata的事务相关信息会存储在数据库中。使用数据库模式可以支持多个seata-server启动,实现seata-server高可用。

这里为简单起见,本文将:

  • 在registry.conf文件中将registry.type=nacos(并将nacos中serverAddr指向Nacos服务端,cluster改为beijing);config.type=file。
  • 在file.conf文件中将store.mode=file。

3、启动seata-server服务端

./seata-server.sh -h 39.100.80.168 &

还可以加启动选项:
    --help 显示帮助
    -h: 本Seata服务向Nacos等注册时,以哪个IP信息作为Seata服务对外暴露IP(本选项不是指定本地侦听IP)。
        对于服务器是阿里云ESC等有NAT转换特别有用
    -p: The port to listen. Default: 8091
    -m: 服务端undo log store mode : file、db. Default: file
    -n: Server node,多个Server时,需区分各自节点,用于生成不同区间的transactionId,以免冲突
    -e: 多环境配置参考 http://seata.io/en-us/docs/ops/multi-configuration-isolation.html

4、查看注册结果。由于在registry.conf文件中将registry.type=nacos。所以在Nacos中可以看到注册的服务。

点看详情,注意查看集群信息(下图中集群名源于registry.conf下的cluster设置):

 六、Seata客户端(AT模式)

   1、应要使用Seata,在前例工程Maven中增加依赖。pom.xml如下:

<!-- 前面省略 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
            <version>${springcloudalibaba.version}</version>
        </dependency>
<!-- 后面省略 -->
  • 以上通过spring-cloud-starter-alibaba-seata:2021.1版本,通过seata-spring-boot-starter:1.3.0,而实际依赖为seata:1.3.0版本。
  • 若使用MySQL的版本≥8.0.23,则会报错“i.s.r.d.u.parser.JacksonUndoLogParser    : json decode exception, Cannot construct instance of `java.time.LocalDateTime` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)”。 Seata官方说在1.4.2中已修复此问题,但实际测试发现Seata1.4.2还没有修复到位。因此MySQL数据库版本因为小于等于8.0.22才能避免此错误。具体见https://github.com/seata/seata/issues/3620#

另:

  • 上面依赖使用了 spring-cloud-starter-alibaba-seata,而不是seata-spring-boot-starter。因为spring-cloud-starter-alibaba-seata已经做了服务之间调用的拦截SeataHandlerInterceptor以实现各个服务调用时传递全局事务XID信息,直接使用即可,比较方便。
  • 若依赖不是使用seata-spring-boot-starter(或spring-cloud-starter-alibaba-seata),而是直接使用seata-all,则还需要额外编写数据源代理代码。 因为seata-spring-boot-starter已经实现了数据源代理且seata.enable-auto-data-source-proxy默认为true。具体见官方《Seata常见问题  第20》http://seata.io/zh-cn/docs/overview/faq.html

   2、各个微服务本地数据库中,确保参与分布式事务的业务表都具有PK主键(否则Seata会报错“Could not found any index in the table” )。  Seata目前只支持单列主键,不支持复合主键。  具体见官方《Seata常见问题  第13》http://seata.io/zh-cn/docs/overview/faq.html

   3、由于使用Seata AT模式,需要在各个微服务使用的应用数据库中创建undo_log表(这里不是Seata服务端的数据库,而是客户端各个微服务的业务数据库)。

     创建表的SQL语句脚本来源参见本文附录A说明。这里使用AT模式,以MySQL为例(https://github.com/seata/seata/blob/develop/script/client/at/db/mysql.sql)在payment、order两个服务所使用的数据库分别创建下表:

-- for AT mode you must to init this sql for you business database. the seata server not need it.
CREATE TABLE IF NOT EXISTS `undo_log`
(
    `branch_id`     BIGINT       NOT NULL COMMENT 'branch transaction id',
    `xid`           VARCHAR(128) NOT NULL COMMENT 'global transaction id',
    `context`       VARCHAR(128) NOT NULL COMMENT 'undo_log context,such as serialization',
    `rollback_info` LONGBLOB     NOT NULL COMMENT 'rollback info',
    `log_status`    INT(11)      NOT NULL COMMENT '0:normal status,1:defense status',
    `log_created`   DATETIME(6)  NOT NULL COMMENT 'create datetime',
    `log_modified`  DATETIME(6)  NOT NULL COMMENT 'modify datetime',
    UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = InnoDB
  AUTO_INCREMENT = 1
  DEFAULT CHARSET = utf8 COMMENT ='AT transaction mode undo table';

   注:表名`undo_log`可以修改。若修改,需要同时修改建表SQL语句和微服务配置seata.client.undo.log-table=值

4、在各个微服务中分别配置Seata相关信息。由于payment、order服务本身由Nacos配置中心进行管理,而且两个服务的配置内容是相同的,因此在配置中心共同通用commonshare.properties增加以下Seata相关配置信息

#================Seata Client Config============
#是否启用Seata(默认启用)
seata.enabled=true

# 定义本服务的事务组(可以每个应用独立取名,也可以不同的应用使用相同的名字)
seata.tx-service-group=mytest-tx-group

# 指定逻辑事务组映射到vgroup-mapping(等号左侧为事务分组名,vgroup-mapping的值需要与seata-server中registry.conf中的cluster保持一致)
seata.service.vgroup-mapping.mytest-tx-group=beijing

seata.registry.type=nacos
seata.registry.nacos.server-addr=39.100.80.168:8848
seata.registry.nacos.application=seata-server
seata.registry.nacos.group=SEATA_GROUP

5、在需要分布式事务的整个业务流程入口增加 @GlobalTransactional 注解。这里order订单服务是整个分布式事务逻辑的入口,因此注解增加在OrderController.java上,内容如下:

@RestController
public class OrderController {

    @Autowired
    private IPaymentServiceClient paymentServiceClient;

    @Autowired
    private JdbcTemplate jdbcTemplate;

    Logger logger = LoggerFactory.getLogger(OrderController.class);

    boolean forcefail = true;

    @GetMapping("/consumer/{orderid}")
    @GlobalTransactional(timeoutMills = 28000, name = "gts-seata-example")
    public ResponseEntity<String> consumerFeign(@PathVariable("orderid") Long orderid) {
        logger.info("全局事务XID=[{}], 事务BranchType=[{}] ", RootContext.getXID(), RootContext.getBranchType());
        String result = paymentServiceClient.dodopay(orderid).getBody(); // 调用支付服务进行支付
        logger.info("[paymentService result]: {}", result);

        jdbcTemplate.update("insert T_Order(order_id, address, remark) values (" + orderid + ", 'dizhi', '"+result+"')");

        //模拟在支付完成后,本订单事务后续处理过程中发生异常后,全局回滚功能
        if (forcefail) {
            throw new RuntimeException("模拟在支付完成后,本订单事务后续处理过程中发生异常!");
        }

        return ResponseEntity.ok ("调用订单服务完成。 订单orderid:" + orderid + ",   调用支付返回的Body:" + result);
    }
}

       注解选项:timeoutMills是超时时间,name是事务的名字, rollbackFor指定函数抛出哪些异类class会进行全局回滚(不指定默认为RuntimeException)。noRollbackFor指定函数抛出哪些异类class不会进行全局回滚。

      注:全局事务的整体提交还是回滚,是由全局事务的发起方(即 @GlobalTransactional 所在的服务)来决定的。即若全局应commt时,则由发起方告诉TC(seata-server),再由TC通知各个branch完成本地提交。 若全局应rollback时,则由发起方告诉TC(seata-server),再由TC通知各个branch完成本地回滚。 

         因此在服务调用链路中,必须将异常抛出至全局事务的发起方,从而被全局事务发起方的 @GlobalTransactional 注解感知到。

6、(可选)为了更好的观察XID的传递情况。在PaymentController.java中增加日志

@RestController
public class PaymentController {
    @Value("${server.port}")
    private int myport;

    @Autowired
    private JdbcTemplate jdbcTemplate;

    Logger logger = LoggerFactory.getLogger(PaymentController.class);

    @GetMapping("/dopay/{orderid}")
    public ResponseEntity<String> paylogic(@PathVariable("orderid") Long orderid) {
        logger.info("全局事务XID=[{}], 事务BranchType=[{}] ", RootContext.getXID(), RootContext.getBranchType());
        int insert_rows = jdbcTemplate.update("insert into T_PAY (order_id, amount) values (" + orderid +", 999)");
        logger.info("支付服务successful! orderid=" + orderid + ", 支付成功。 支付服务的端口为port=" + myport);
        return ResponseEntity.ok("支付服务successful! orderid=" + orderid + ", 支付成功。 支付服务的端口为port=" + myport);
    }
}

    7、分别运行payment、order服务。测试。curl  http://localhost:8888/consumer/66   

          可以发现两个服务的业务数据库要么同时生效有数据,要么同时没有数据,实现了分布式事务一致性。

 七、Seata服务端调整配置

  上面在seata-server使用了config.type=file,store.mode=file。这两者都不适合生产环境。因此需要进行调整:即将config.type=file改为Nacos配置中心、store.mode=file改为由数据库db存放。

   1、获取Seata服务端数据库建表SQL脚本。 脚本来源参见本文附录A说明 (即https://github.com/seata/seata/tree/develop/script/config-center

 2、执行建表SQL脚本。 先在MySQL数据库创建名为“seata”的schema。然后在该schema下,执行以上SQL脚本(四张表:`global_table`、`branch_table`、`lock_table`、`distributed_lock`)

 3、进入服务端seata软件安装目录下conf目录,编辑registry.conf文件,如下:

registry {
  # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
  type = "nacos"

  nacos {
    application = "seata-server"
    serverAddr = "39.100.80.168:8848"
    group = "SEATA_GROUP"
    namespace = ""
    cluster = "beijing"
    username = ""
    password = ""
  }
}

config {
  # file、nacos 、apollo、zk、consul、etcd3
  type = "nacos"

  nacos {
    serverAddr = "39.100.80.168:8848"
    namespace = ""
    group = "SEATA_GROUP"
    username = ""
    password = ""
    dataId = "seataServer.properties"
  }
}
  • 保持服务注册中心registry.type=nacos不变(即Seata继续使用nacos注册中心,nacos下具体serverAddr、group、cluster等配置按实际情况)。
  • 修改config.type=nacos(nacos下具体serverAddr、group、dataId等配置按实际情况)

  4、获取配置中心的配置项内容模板。 配置内容来源参见本文附录A说明 (即https://github.com/seata/seata/tree/develop/script/config-center

  5、以获取“config.txt”文件内容作为模板参考 (各配置项的含义说明参见:https://seata.io/zh-cn/docs/user/configurations.html)。

       因为“config.txt”文件原始内容比较多,需要从中选择(其他配置项不必显示设置,保持默认值即可)。另外“config.txt”即有对Seata服务端的配置,也有对Seata客户端(即各微服务)的定义。这里只选择与服务端有关且比较常用配置,选取修改后配置内容如下:

#========= Seata Server Config:Server端连接数据库信息
store.mode=db
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.cj.jdbc.Driver
store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&rewriteBatchedStatements=true
store.db.user=root
store.db.password=Pwd_1234
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

   人工在Nacos配置中心界面上,将以上内容配置拷贝到Nacos,如下图。配置中心的dataId=seataServer.properties,group=SEATA_GROUP等必须与registry.conf文件中定义的一致。  (网上文章大多通过nacos-config.sh的Shell脚本将以上内容推送到Nacos中。不过建议最好还是人工配置,比较方便且过程自主可控)

 6、重启seata-server端。./seata-server.sh -h 39.100.80.168 &

 7、测试可以发现:若全局事务整体成功提交或成功回滚,在seata-server的三张Tables中不会留下数据(实际SQL动作过程是先insert、再update、最后delete)。只有未完成的全局事务,三张Tables才会留有数据。

附录A:Seata需要的SQL等官方脚本

见安装目录seata/conf/README-zh.md. 该文件内如如下:

# 脚本说明

## [client](https://github.com/seata/seata/tree/develop/script/client) 

> 存放用于客户端的配置和SQL

- at: AT模式下的 `undo_log` 建表语句
- conf: 客户端的配置文件
- saga: SAGA 模式下所需表的建表语句
- spring: SpringBoot 应用支持的配置文件

## [server](https://github.com/seata/seata/tree/develop/script/server)

> 存放server侧所需SQL和部署脚本

- db: server 侧的保存模式为 `db` 时所需表的建表语句
- docker-compose: server 侧通过 docker-compose 部署的脚本
- helm: server 侧通过 Helm 部署的脚本
- kubernetes: server 侧通过 Kubernetes 部署的脚本

## [config-center](https://github.com/seata/seata/tree/develop/script/config-center)

> 用于存放各种配置中心配置项模板和脚本,执行时都会读取 `config.txt`配置文件,并写入配置中心

- nacos: 用于向 Nacos 中添加配置
- zk: 用于向 Zookeeper 中添加配置,脚本依赖 Zookeeper 的相关脚本,需要手动下载;ZooKeeper相关的配置可以写在 `zk-params.txt` 中,也可以在执行的时候输入
- apollo: 向 Apollo 中添加配置,Apollo 的地址端口等可以写在 `apollo-params.txt`,也可以在执行的时候输入
- etcd3: 用于向 Etcd3 中添加配置
- consul: 用于向 consul 中添加配置

猜你喜欢

转载自blog.csdn.net/zyplanke/article/details/121216853
今日推荐