目录
一、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概念
请先阅读官网文档(必读知识包括):
- Seata是什么:http://seata.io/zh-cn/docs/overview/what-is-seata.html
- 各事务模式:http://seata.io/zh-cn/docs/dev/mode/at-mode.html
- 事务分组:http://seata.io/zh-cn/docs/user/txgroup/transaction-group-and-ha.html
事务分组概念释疑
其中事务分组及相关的几个概念参数,网上大多文章有误导。正确的理解为:
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名) |
网上文章常见的错误为:
- 网上这几个概念分不清楚(其实主要怪Seata官网文档写得不好,网上很多文章不假思索的抄袭而导致的);
- 网上错误理解为上面三个参数还需要在seata-server服务端配置。实际上这些参数都是在客户端配置,不是服务端的配置;
- 网上错误要求把registry.conf与file.conf文件需要拷贝到客户端(微服务)的resources目录下,对于SpringBoot应用其实完全不需要。
- 其他:官网的文档、范例与最新的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 中添加配置