Spring Cloud集成Seata分布式事务

1. Nacos简介

Nacos(Dynamic Naming and Configuration Service)一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。

Nacos帮助我们更敏捷和容易的构建、交付和管理微服务平台,Nacos是构建以”服务”为中新的现代应用架构(例如微服务范式、云原生范式)的服务基础设施。

1.1 Nacos的关键特性

Nacos支持几乎所有主流类型的”服务”的发现、配置、管理;

  • 服务发现和服务健康监测

    Nacos 支持基于 DNS 和基于 RPC 的服务发现。服务提供者使用 原生SDKOpenAPI、或一个独立的Agent TODO注册 Service 后,服务消费者可以使用DNS TODO 或HTTP&API查找和发现服务。


    Nacos提供对服务的实时的健康检查,阻止向不健康的主机或服务实例发送请求。`Nacos` 支持传输层 (`PING` 或 `TCP`)和应用层 (如 HTTP、MySQL、用户自定义)的健康检查。 对于复杂的云环境和网络拓扑环境中(如 VPC、边缘网络等)服务的健康检查,Nacos 提供了 agent 上报模式和服务端主动检测2种健康检查模式。Nacos 还提供了统一的健康检查仪表盘,帮助您根据健康状态管理服务的可用性及流量。
  • 动态配置服务

    1. 动态配置服务可以让您以中心化、外部化和动态化的方式管理所有环境的应用配置和服务配置。

    2. 动态配置消除了配置变更时重新部署应用和服务的需要,让配置管理变得更加高效和敏捷。

    3. 配置中心化管理让实现无状态服务变得更简单,让服务按需弹性扩展变得更容易。

    4. Nacos 提供了一个简洁易用的UI (控制台样例 Demo) 帮助您管理所有的服务和应用的配置。Nacos 还提供包括配置版本跟踪、金丝雀发布、一键回滚配置以及客户端配置更新状态跟踪在内的一系列开箱即用的配置管理特性,帮助您更安全地在生产环境中管理配置变更和降低配置变更带来的风险

  • 动态DNS服务

    动态DNS服务支持权重路由,让您更容易实现中间层负载均衡、更灵活的路由策略、流量控制以及数据中心内网的简单DNS解析服务。动态DNS服务还能让我们更容易地实现以DNS协议为基础的服务发现,以帮助消除耦合到厂商私有服务发现API上的风险。

    Nacos 提供了一些简单的 DNS APIs TODO 帮助您管理服务的关联域名和可用的 IP:PORT 列表.

  • 服务及其元数据管理

    Nacos 能让您从微服务平台建设的视角管理数据中心的所有服务及元数据,包括管理服务的描述、生命周期、服务的静态依赖分析、服务的健康状态、服务的流量管理、路由及安全策略、服务的 SLA 以及最首要的 metrics 统计数据

1.2 Nacos概念

  1. 地域

    物理的数据中心,资源创建成功后不能更改

  2. 可用区

    统一地域内,电力和网络互相独立的物理区域。同一可用区内,实例的网络的延迟较低

  3. 接入点

    地域的某个服务的入口域名

  4. 命名空间

    用于进行租户粒度的配置隔离。不同命名空间下,可以存在相同的Group或DataID 的配置。Namespace的常用场景之一是不同环境的配置的区分隔离,例如开发测试环境和生产环境的资源(配置、服务))隔离等。

  5. 配置

    在系统开发过程中,开发者通常会将一些需要变更的参数、变量等从代码中分离出来独立管理,以独立的配置文件的形式存在。目的是让静态的系统工件或者交付物(如 WAR,JAR 包等)更好地和实际的物理运行环境进行适配。配置管理一般包含在系统部署的过程中,由系统管理员或者运维人员完成。配置变更是调整系统运行时的行为的有效手段。

  1. 配置管理

    系统配置的编辑、存储、分发、变更管理、历史版本管理、变更审计等所有与配置相关的活动

更多概念请看:https://nacos.io/zh-cn/docs/concepts.html

1.3 基本架构

  1. 服务 (Service)

    服务是指一个或一组软件功能(例如特定信息的检索或一组操作的执行),其目的是不同的客户端可以为不同的目的重用(例如通过跨进程的网络调用)。Nacos 支持主流的服务生态,如 Kubernetes Service、gRPC|Dubbo RPC Service 或者 Spring Cloud RESTful Service。

  2. 服务注册中心 (Service Registry)

    服务注册中心,它是服务,其实例及元数据的数据库。服务实例在启动时注册到服务注册表,并在关闭时注销。服务和路由器的客户端查询服务注册表以查找服务的可用实例。服务注册中心可能会调用服务实例的健康检查 API 来验证它是否能够处理请求。

  3. 服务元数据 (Service Metadata)

    服务元数据是指包括服务端点(endpoints)、服务标签、服务版本号、服务实例权重、路由规则、安全策略等描述服务的数据。

  4. 服务提供方 (Service Provider)

    是指提供可复用和可调用服务的应用方。

  5. 服务消费方 (Service Consumer)

    是指会发起对某个服务调用的应用方。

  6. 配置 (Configuration)

    在系统开发过程中通常会将一些需要变更的参数、变量等从代码中分离出来独立管理,以独立的配置文件的形式存在。目的是让静态的系统工件或者交付物(如 WAR,JAR 包等)更好地和实际的物理运行环境进行适配。配置管理一般包含在系统部署的过程中,由系统管理员或者运维人员完成这个步骤。配置变更是调整系统运行时的行为的有效手段之一。

  7. 配置管理 (Configuration Management)

    在数据中心中,系统中所有配置的编辑、存储、分发、变更管理、历史版本管理、变更审计等所有与配置相关的活动统称为配置管理。

  8. 名字服务 (Naming Service)

    提供分布式系统中所有对象(Object)、实体(Entity)的“名字”到关联的元数据之间的映射管理服务,例如 ServiceName -> Endpoints Info, Distributed Lock Name -> Lock Owner/Status Info, DNS Domain Name -> IP List, 服务发现和 DNS 就是名字服务的2大场景。

  9. 配置服务 (Configuration Service)

    在服务或者应用运行过程中,提供动态配置或者元数据以及配置管理的服务提供者。

2. Nacos安装

可以通过源码和发行包两种方式来获取Nacos

2.1 源码方式

1
2
3
4
5
6
7
git clone https://github.com/alibaba/nacos.git
cd nacos/
mvn -Prelease-nacos -Dmaven.test.skip=true clean install -U
ls -al distribution/target/

// change the $version to your actual path
cd distribution/target/nacos-server-2.3.0-SNAPSHOT/nacos/bin

2.2 发行包

从github上下载稳定版本 nacos-server-$version.zip

1
2
3
unzip nacos-server-$version.zip 或者 tar -xvf nacos-server-$version.tar.gz

cd nacos/bin

2.3 鉴权以及访问控制台

按照官方文档配置启动,默认是不需要登录的,这样会导致配置中心对外直接暴露。而启用鉴权之后,需要在使用用户名和密码登录之后,才能正常使用nacos

具体鉴权可以查看官网:

1
2
3
4
5
#进入nacos安装目录
cd ./distribution/target/nacos-server-2.3.0-SNAPSHOT/nacos/conf

#编辑配置文件
vim application.properties

nacos.core.auth.server.identity.key and nacos.core.auth.server.identity.value
修改配置文件

1
2
3
4
5
6
7
8
9
10
### If turn on auth system:
nacos.core.auth.enabled=true

#自定义密钥
#the length of secret key must great than or equal 32 bytes; And the secret key must be encoded by base64.
nacos.core.auth.server.identity.key=xiaoyuge
nacos.core.auth.server.identity.value=xiaoyuge

#使用的是官网给的
nacos.core.auth.plugin.nacos.token.secret.key=SecretKey012345678901234567890123456789012345678901234567890123456789

1
2
3
4
5
6
7
8
cd ../bin
#单机模式运行, 如果是window,使用 startup.cmd -m standalone
sh startup.sh -m standalone
# 查看日志
cd ../logs
tail -100f start.out

#关闭 命令 sh ./shutdown.sh

我使用的是源码的方式运行Nacos,启动日志如下:

通过浏览器访问Nacos的控制台http://localhost:8848/nacos 用户名和密码都是nacos

3. Seata搭建

在使用微服务中,单体事务注解 @Transcational 就不适用来,需要采用分布式事务解决方案

Seata一款开源的分布式事务解决方案,致力于在微服务架构下提供性能和简单易用的分布式事务服务。

Seata是一个分布式事务,Seata服务端也是一个微服务,需要和其他微服务一样需要注册中心和配置中心,同时事务回滚,需要数据库日志记录

  • 注册和配置中心: nacos

  • 数据库: mysql

3.1 下载

进入Seata官网, 下载版本是1.6.1。解压文件后进入seata文件

3.2 建表

新建数据库seata,然后在seata文件夹里面的script文件找到server-> db -> mysql.sql, 然后在数据库执行sql语句。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
-- -------------------------------- The script used when storeMode is 'db' --------------------------------
-- the table to store GlobalSession data
CREATE TABLE IF NOT EXISTS `global_table`
(
`xid` VARCHAR(128) NOT NULL,
`transaction_id` BIGINT,
`status` TINYINT NOT NULL,
`application_id` VARCHAR(32),
`transaction_service_group` VARCHAR(32),
`transaction_name` VARCHAR(128),
`timeout` INT,
`begin_time` BIGINT,
`application_data` VARCHAR(2000),
`gmt_create` DATETIME,
`gmt_modified` DATETIME,
PRIMARY KEY (`xid`),
KEY `idx_status_gmt_modified` (`status` , `gmt_modified`),
KEY `idx_transaction_id` (`transaction_id`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4;

-- the table to store BranchSession data
CREATE TABLE IF NOT EXISTS `branch_table`
(
`branch_id` BIGINT NOT NULL,
`xid` VARCHAR(128) NOT NULL,
`transaction_id` BIGINT,
`resource_group_id` VARCHAR(32),
`resource_id` VARCHAR(256),
`branch_type` VARCHAR(8),
`status` TINYINT,
`client_id` VARCHAR(64),
`application_data` VARCHAR(2000),
`gmt_create` DATETIME(6),
`gmt_modified` DATETIME(6),
PRIMARY KEY (`branch_id`),
KEY `idx_xid` (`xid`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4;

-- the table to store lock data
CREATE TABLE IF NOT EXISTS `lock_table`
(
`row_key` VARCHAR(128) NOT NULL,
`xid` VARCHAR(128),
`transaction_id` BIGINT,
`branch_id` BIGINT NOT NULL,
`resource_id` VARCHAR(256),
`table_name` VARCHAR(32),
`pk` VARCHAR(36),
`status` TINYINT NOT NULL DEFAULT '0' COMMENT '0:locked ,1:rollbacking',
`gmt_create` DATETIME,
`gmt_modified` DATETIME,
PRIMARY KEY (`row_key`),
KEY `idx_status` (`status`),
KEY `idx_branch_id` (`branch_id`),
KEY `idx_xid` (`xid`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4;

CREATE TABLE IF NOT EXISTS `distributed_lock`
(
`lock_key` CHAR(20) NOT NULL,
`lock_value` VARCHAR(20) NOT NULL,
`expire` BIGINT,
primary key (`lock_key`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4;

INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('AsyncCommitting', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryCommitting', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryRollbacking', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('TxTimeoutCheck', ' ', 0);

全局事务会话由: 全局事务global_table、分支事务branch_table、全局锁 lock_table

3.3 修改application.yml

修改application.yml文件中的注册中心、配置中心、存储模式配置,参考resources/application.example.yml文件,修改后如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
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:
config:
# support: nacos, consul, apollo, zk, etcd3
type: file
registry:
# support: nacos, eureka, redis, zk, consul, etcd3, sofa
type: nacos
nacos:
application: seata-server
server-addr: 127.0.0.1:8848
namespace:
group: SEATA_GROUP
cluster: default
username: nacos
password: nacos
##if use MSE Nacos with auth, mutex with username/password attribute
#access-key: ""
#secret-key: ""
store:
#存储模式支持: file 、 db 、 redis
mode: db
db:
datasource: druid
db-type: mysql
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/seata?rewriteBatchedStatements=true
user: root
password: xiaoyuge
min-conn: 5
max-conn: 100
global-table: global_table
branch-table: branch_table
lock-table: lock_table
distributed-lock-table: distributed_lock
query-limit: 100
max-wait: 5000
# 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,/**/*.ico,/console-fe/public/**,/api/v1/auth/login

3.4 启动Seata服务

启动seata-server,控制台登录页面如下,账号和密码均为seata

4. 项目搭建

4.1 业务背景

用户购买商品的业务逻辑,整个业务逻辑由三个微服务提供支持

  • 仓储服务: 对给定的商品扣除仓储数量

  • 订单服务: 根据采购需求创建订单

  • 账户服务: 从用户扣除金额

架构

4.2 业务表创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
DROP TABLE IF EXISTS `t_account`;
CREATE TABLE `t_account`
(
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` varchar(255) DEFAULT NULL,
`amount` double(14, 2
) DEFAULT '0.00',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of t_account
-- ----------------------------
INSERT INTO `t_account`
VALUES ('1', '1', '4000.00');

-- ----------------------------
-- Table structure for t_order
-- ----------------------------
DROP TABLE IF EXISTS `t_order`;
CREATE TABLE `t_order`
(
`id` int(11) NOT NULL AUTO_INCREMENT,
`order_no` varchar(255) DEFAULT NULL,
`user_id` varchar(255) DEFAULT NULL,
`commodity_code` varchar(255) DEFAULT NULL,
`count` int(11) DEFAULT '0',
`amount` double(14, 2
) DEFAULT '0.00',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=64 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of t_order
-- ----------------------------

-- ----------------------------
-- Table structure for t_stock
-- ----------------------------
DROP TABLE IF EXISTS `t_stock`;
CREATE TABLE `t_stock`
(
`id` int(11) NOT NULL AUTO_INCREMENT,
`commodity_code` varchar(255) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
`count` int(11) DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `commodity_code` (`commodity_code`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of t_stock
-- ----------------------------
INSERT INTO `t_stock`
VALUES ('1', 'C201901140001', '水杯', '1000');

-- ----------------------------
-- Table structure for undo_log
-- 注意此处0.3.0+ 增加唯一索引 ux_undo_log
-- ----------------------------
DROP TABLE IF EXISTS `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,
PRIMARY KEY (`id`),
UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of undo_log
-- ----------------------------
SET
FOREIGN_KEY_CHECKS=1;

4.3 服务创建

以order服务为例,引入依赖、配置参数、提供创建订单接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<dependencies>
<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>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>

application.properties配置参数

1
2
3
4
5
6
7
8
9
10
11
12
server.port=81
spring.application.name=order
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.cloud.nacos.username=nacos
spring.cloud.nacos.password=nacos
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/seata_samples?allowPublicKeyRetrieval=true&useSSL=false&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true
spring.datasource.username=root
spring.datasource.password=root
mybatis-plus.mapper-locations=classpath:mapper/*.xml
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

提供创建订单接口

1
2
3
4
5
6
7
8
9
10
@RequestMapping("/add")
public void add(String userId, String commodityCode, Integer count, BigDecimal amount) {
Order order = new Order();
order.setOrderNo(UUID.randomUUID().toString());
order.setUserId(userId);
order.setAmount(amount);
order.setCommodityCode(commodityCode);
order.setCount(count);
orderService.save(order);
}

4.4 聚合服务

business服务远程调用仓储、订单、账户服务,完成下单流程。

  1. 引入依赖

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    <dependencies>
    <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>
    </dependency>
    <dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
    </dependency>
    <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    </dependency>
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    </dependencies>
  2. application.properties配置参数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    server.port=80
    spring.application.name=business
    spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
    spring.cloud.nacos.username=nacos
    spring.cloud.nacos.password=nacos
    spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
    spring.datasource.url=jdbc:mysql://127.0.0.1:3306/seata_samples?allowPublicKeyRetrieval=true&useSSL=false&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true
    spring.datasource.username=root
    spring.datasource.password=root
    service.disableGlobalTransaction=false
    # 连接超时时间
    ribbon.ConnectTimeout=3000
    # 响应超时时间
    ribbon.ReadTimeout=5000
  3. 声明account、stock、order的feign接口

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    //账户服务
    @FeignClient(value = "account")
    public interface AccountFeign {
    @RequestMapping("/account/reduce")
    public void reduce(@RequestParam("userId") String userId, @RequestParam("amount") BigDecimal amount);
    }
    //订单服务
    @FeignClient(value = "order")
    public interface OrderFeign {
    @RequestMapping("/order/add")
    public void add(@RequestParam("userId") String userId, @RequestParam("commodityCode") String commodityCode, @RequestParam("count") Integer count, @RequestParam("amount") BigDecimal amount);
    }
    //仓储服务
    @FeignClient(value = "stock")
    public interface StockFeign {
    @RequestMapping("/stock/deduct")
    public void deduct(@RequestParam("commodityCode") String commodityCode, @RequestParam("count") Integer count);
    }
  4. 全局事务开启,调用feign接口

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    @Autowired
    private OrderFeign orderFeign;

    @Autowired
    private StockFeign stockFeign;

    @Autowired
    private AccountFeign accountFeign;

    @GlobalTransactional
    @RequestMapping("/toOrder")
    public void toOrder(String userId, String commodityCode, Integer count, BigDecimal amount) {
    accountFeign.reduce(userId, amount);
    stockFeign.deduct(commodityCode, count);
    orderFeign.add(userId, commodityCode, count, amount);
    }
  5. 测试验证

    当前资金账户4000,库存1000,模拟用户购买商品2000个,消费4000,业务调用后,数据库数据状态应该如下:

    • 用户资金满足4000,数据库更新用户资金为0
    • 商品库存不足2000,异常
    • business服务提交全局回滚
    • 资金服务回滚操作,更新资金为4000

  6. 验证

    • 浏览器访问
      http://127.0.0.1/business/toOrder?userId=1&commodityCode=C201901140001&count=2000&amount=4000
      
    • account、stock服务日志观察

    • 数据库数据依然为原始状态

4.5 注意事项

  1. Seata1.5版本的mysql驱动是5.7,需要8,在libs文件夹删除mysql-connector-java-5.xx.jar替换为mysql-connector-java-8.xx.jar即可
  1. Spring Boot &Spring Cloud&Spring Cloud Alibaba版本兼容问题