MySQL的ACID事务特性原子性和持久性就要靠undo和redo日志实现

undo的原理:

为了满足事务的原子性,操作数据前首先将数据备份到undo log,然后进行数据修改。

如果出现错误或者用户执行了Rollback语句,系统可以利用undo log中的备份将数据恢复到事务操作前的状态

数据库写入数据到磁盘之前,会先把数据保存在内存中,事务提交才回把数据写入到磁盘中。
    undo log实现原子性和持久性的简化过程
    加入要修改两条数据,A,B
    1.事务开始
    2.A=1 写入到undo log
    3.修改 A=2
    4.将undo log写入到磁盘
    5.将数据写入到磁盘
    6.事务提交

如何保证持久性:

事务提交前,会把修改事务放到磁盘前,只要事务提交,数据就能持久化。

如何保证原子性:

  1. 每次对数据库修改都会把数据写入到undo log 里面,需要回滚时,读取undo log日志恢复数据
  2. 若数据已经写入到磁盘,在事务提交前出错,则事务并未提交,需要回滚,undo log已经被持久化,可以根据undo log 来恢复数据
  3. 若在数据写入磁盘前奔溃,此时数据并未持久化到磁盘,依然保持事务之前的状态。重启一下就可以了。

Redo日志

和undo相反,redo log记录的是最新的数据的备份,在事务提交前只需要将redo log持久化即可,不需要将数据持久化,减少io次数。

undo和redo事务的简化过程:

a.事务开始
b.A=2 写入到undo log buffer
C.修改A=4  把A=4记录到redo log buffer里面
D.把undo log写入到磁盘
E.把redo log写入到磁盘
F.提交事务

如果提交事务后,系统崩了

那内存中的A=4也会丢失,可以从redo log 中恢复数据

数据写入到磁盘是异步操作

数据写入磁盘有两种方式:
随机写入,性能比较差
顺序写入,性能好。

  • 之前是写undo和数据到磁盘,现在是写undo和redo到磁盘,似乎没有减少io次数
  1. 数据库数据写入是随机io,性能很差
  2. redo log在初始化时会开辟一段连续的内存空间,写入是顺序io,性能好。
  3. 实际上undo log并不是直接写入到磁盘,而是先写入到undo log buffer中,当redo log持久化时undo log就同时持久化到磁盘了
  4. 用undo log 和redo log只需要经过一次磁盘就可以了,undo log并不是直接写入到磁盘而是写入到redo log里面,所以经过一次io

undo log和数据写入磁盘需要经过两次io,性能比较差。

  • 当redo log buffer内存满了也会写入到磁盘
问题:
    如果在事务提交之前,redo log bugger内存满了,redo log会把数据写入到磁盘,然后事务回滚,这时候服务宕机了,怎么办?
    数据库恢复机制,
        第一种,只读取undo log
        第二种,解析redo log 因为会做一些运算会被CPU制约
        第三种,直接恢复redo log 当redo log恢复完以后再去找恢复好的undo log还原

一、分布式事务:

分布式事务是指在分布式系统下,跨越多个微服务或多个数据库的情况下产生的事务

二、解决分布式系统的思路

从CAP定理和base理论说起

任何分布式系统都会满足三个指标 CAP,分布式系统无法同时满足一下三点,只能满足其中两点

CAP定理的含义:

Consistency(一致性)

Availability (可用性)

Partition tolerance(分区容错性)

Partition tolerance 分区容错性

大多数分布式系统都分布在多个子网络,每个子网络就叫一个区,分区容错性的意思就是指,区间通信可能失败。比如,一个一台服务器在上海,一台服务区在浙江,这就是两个区,他们之间可能因网络问题无法通信。

Availability (可用性)

意思是只要收到用户请求,服务器就必须给出响应(对错无关)

Consistency(一致性)

保证一致性,让服务器1写操作时,同时给服务器2发送信息,让服务器2也发生改变,保证一致性




mysql执行undo文件 mysql中undo和redo_分布式


CA冲突

如上图,在服务器1给服务器2发送消息时,为了保证消息一致性,这个时候,服务器2需要拦截请求,直到消息更新完成,所以就造成了服务器2在这段时间没有响应,所以CA不能同时满足。

保证服务器2的一致性,那么在服务器1必须在写操作时,锁定服务器2的读操作和写操作,只有数据同步后,才能重新开放读写,锁定期间,服务器2不能读写,所以没有可用性。

单点架构能同时满足CA;对一致性要求高的场景需要同时满足CP、例如zookeeper,在服务节点间数据同步时,服务对外不可用;对可用性要求较高的场景使用AP、例如Eureka,不许保证注册中心随时可用,不然拉取不到服务就可能出现问题

base理论

基本可用(Basically Available)、

软状态(Soft-state)、

最终一致性(Eventually Consistency)。

最终一致性,当服务器1同步数据到服务器2时,期间的消耗的时间需要时间过长比如8秒,不在接受范围,等一段时间以后才会一致,就叫最终一致性。如果为1秒,在可接受范围,就叫弱一致。等一小段时间就可用了,叫基本可用。

CP方式:

现在如果要满足事务的强一致性,就必须在订单服务数据库锁定的同时,对库存服务、用户服务数据资源同时锁定。等待三个服务业务全部处理完成,才可以四方资源,此时如果有其他请求要操作被锁定的资源就会被阻塞,这就就是满足了CP,这就是强一致,若可用。

AP方式:

三个服务的对应数据库各自独立利执行自己的业务,执行本地事务,不要求互相锁定资源。但是这个中间状态下,我们去访问数据库,可能遇到数据不一致的情况,不过我们需要做一些后补措施,保证在经过一段时间后,数据最终满足一致性。这就是高可用,弱一致(最终一致)。

由上面的两种思想,延伸出了很多的分布式事务解决方案:

XA

TCC

可靠消息最终一致

AT


mysql执行undo文件 mysql中undo和redo_java_02


三、分布式解决方法

分阶段提交

两阶段提交协议(2PC TWO-Phase-Commit)

两阶段提交协议是 X/open组织(即Open Group)定义了分布式事务处理的DTP模型提出的一种协议;该模型包括的角色

  • 应用程序(AP):我们的微服务
  • 事务管理器(TM):全局事务管理者
  • 资源管理器(RM):一般是数据库
  • 通信资源管理器(CRM):是TM和RM间的通信中间件

在该模型中,一个分布式事务(全局事务)可以被拆分成许多个本地事务,运行在不同的AP和RM上。每个本地事务的ACID很好实现,但是全局事务必须保证其中包含的每一个本地事务都能同时成功,若有一个本地事务失败,则所有其它事务都必须回滚。但本地事务处理过程中,并不知道其它事务的运行状态,因此就需要CRM来通知各个本地事务,同步事务执行的状态。

各个本地事务的通信必须有统一的规范,否则不同数据库间就无法通信。XA就是X/open DTP中通信中间件与TM间联系的接口规范,定义了用于通知事务开始、提交、终止、回滚等接口,各个数据库厂商都必须实现这些接口

二阶段提交:

将全局事务分为两个阶段来提交

  1. 阶段一:准备阶段,各个本地事务完成本地事务的准备工作。
  2. 阶段二:执行阶段,各个本地事务根据上一阶段执行结果,进行提交或回滚。

这个过程需要一个协调者(coordinator),还有事务的参与者(voter)

  1. 正常情况:


mysql执行undo文件 mysql中undo和redo_mysql执行undo文件_03


投票阶段:协调组询问各个事务参与者,是否可以执行事务。每个事务参与者执行事务,写入redo和undo日志,然后反馈事务执行成功的信息(agree)

提交阶段:协调组发现每个参与者都可以执行事务(agree),于是向各个事务参与者发出(commit)指令,各个事务参与者提交事务。

第一阶段CRM通知事务开始执行,所以事务把执行结果告诉协调器(这个过程中,一个事务执行完成,会等待其它事务),所有事务都执行成功了,然后协调器通知事务开始提交,

  1. 失败的情况:


mysql执行undo文件 mysql中undo和redo_分布式_04


投票阶段:协调组询问恩各个事务参与者,是否可以执行事务。每个事务参与者执行事务写入redo和undo日志,然后反馈事务执行结果,但只要有一个参与者返回的是Disagree,则说明执行失败。

提交阶段:协调组发现有一个或多个参与者返回的是disagree,认为执行失败。于是想各个事务参与者发出abort指令,各个事务参与者回滚 事务。

二阶段提交的缺点:

单点故障,在事务执行完成后,协调者奔溃


mysql执行undo文件 mysql中undo和redo_mysql执行undo文件_05


阻塞问题

在准备阶段、提交阶段,每个事务参与者都会锁定本地资源,并等待其他事务的执行结果,阻塞时间较长,资源锁定时间太久,因此执行的效率就比较低了。

TCC模式解决分布式事务

TCC模式可以解决2PC中的资源锁定和阻塞问题,减少资源锁定时间。

基本原理:

  • Try:资源的检测和预留
  • Comfirm:执行的业务操作提交;要求Try成功Comfirm一定要成功;
  • Cancel:预留资源释放。

执行分两个阶段:

  • 准备阶段(try):资源的检测和预留
  • 执行阶段(confirm/cancel):根据上一步结果,判断下面的执行方法。如果上一步中所有事务参与者都成功,则这里执行confirm。反之,执行cancel


mysql执行undo文件 mysql中undo和redo_mysql_06


  • try、confirm、cancel都是独立的事务,不受其它参与者的影响,不会阻塞等待它人
  • try、confirm、cancel由程序员在业务层编写,锁粒度有代码控制
例如:

以转账为例,假设账户A原来余额是100元,需要余额扣减30元,如图:


mysql执行undo文件 mysql中undo和redo_mysql_07


  • 第一阶段(try):余额检查,并冻结用户部分金额,此阶段执行完毕,事务已经提交
  • 检查余额是否充足,如果充足,冻结部分余额
  • 在账户表中添加冻结金额字段,值为30,余额不变
  • 第二阶段
  • 提交(confirm):真正的扣款,把冻结金额从余额中扣除,冻结金额清空
  • 修改冻结金额为0,修改余额为100-30=70元;
  • 补偿(cancel):释放之前冻结的金额,并非回滚
  • 余额不变,冻结金额为0

c.优势和缺点:

  • 优势
  • TCC执行的每一个阶段都会提交本地事务并释放锁,并不需要等待其它事务的执行结果。而如果其它事务执行失败,最后不是回滚,而是执行补偿操作。这样就避免了资源的长期锁定和阻塞等待,执行效率比较高,属于性能比较好的分布式事务解决方案。
  • 缺点
  • 代码侵入:需要人为编写代码实现try,confirm,cancel,代码侵入比较多
  • 开发成本高:一个业务需要拆分成3个步骤,分别编写业务实现,业务编写比较复杂
  • 安全性考虑:cancel动作如果执行失败,资源就无法释放,需要引入重试机制,而重试可能导致重复执行,还要考虑重试时的幂等问题。

d.使用场景

  • 对事务有一定的一致性要求(最终一致)
  • 对性能要求较高
  • 开发人员具备较高的编码能力和幂等处理经验

可靠性消息服务

这种实现方式的思路,其实是源于eBay,其基本的设计思想是将远程分布式事务拆分成一系列的本地事务

基本原理

一般分为事务的发起者A和事务的其它参与者B

  • 事务发起者A执行事务
  • 事务发起者A通过MQ将需要执行的事务信息发送给事务参与者B
  • 事务参与者B接收到消息后执行本地事务


mysql执行undo文件 mysql中undo和redo_mysql_08


比如A要给B转账,A在本地事务完成扣完钱后,发送消息到MQ,B从MQ接收消息,进行本地事务,如果失败就重试,不能回滚A的数据。时效性比较差,不能确保什么时候能完成。

注意事项:

  • 事务发起者A必须确保本地事务成功后,小一定发送成功
  • MQ必须保证消息正确投递和持久化保存
  • 事务参与者B必须确保消息最终一定能消费,如果失败需要多次重试
  • 事务B执行失败,会重试,但不会导致事务A回滚

可靠性消息服务能确保最终一致性

如何保证消息一定能发送?

  1. 本地消息表

为了避免消息发送失败或丢失,我们可以把消息持久化到数据库中,实现时有简化版本和解耦版本两种方式

简化版本

原理图:


mysql执行undo文件 mysql中undo和redo_java_09


事务发起者:

  • 开启本地事务
  • 执行事务相关业务
  • 发送消息到MQ
  • 把消息持久化到数据库,标记为已发送
  • 提交本地事务

事务接收者:

  • 接收消息
  • 开启本地事务
  • 处理事务相关业务
  • 修改数据库消息状态为已消费
  • 提交本地事务

额外的定时任务

定时扫描表中超时未消费信息,重新发送

优势:

与TCC相比,实现方式较为简单,开发成本低

缺点:

  • 数据一致性完全依赖于消息服务,因此消息服务必须是可靠的。
  • 需要处理被动业务方的幂等问题
  • 被动业务失败不会导致主动业务的回滚,而是重试被动的业务
  • 事务业务与消息发送业务耦合、业务数据与消息表要在一起

独立消息服务

为了解决上述问题,我们引入一个独立消息服务,来完成对消息的持久化,发送,确认,失败重试等一系列行为,大概的模型如下


mysql执行undo文件 mysql中undo和redo_java_10


一次消息发送的时序图:


mysql执行undo文件 mysql中undo和redo_java_11


RocketMQ事务消息

RocketMQ本身自带了事务消息,可以保证消息的可靠性,原理其实就是自带了本地消息表

RabbitMQ的消息确认

rabbitMQ确保消息不丢失的思路是利用了消息的确认机制,没有使用传统的本地表

  • 生产者确认机制:确保消息从生产者到达MQ不会有问题
  • 消息生产者发送消息到rabbitMQ时,可以设置一个异步的监听器,监听来自MQ的ACk
  • MQ接收到消息后,会返回一个回执给生产者
  • 消息到达交换机后路由失败,会返回失败的ACK
  • 消息路由成功,持久化失败。会返回失败的ACK
  • 消息路由成功,持久化成功,会返回成功ACK
  • 生产者提前编写好不同回执的处理方式
  • 失败回执:等待一定时间后重新发送
  • 成功回执:记录日志等行为
  • 消费者确认机制:确保消息能够被消费者正确消费
  • 消费者需要在监听队列的时候执行手动ACK模式
  • rabbitMQ把消息投递给消息者后,会等待消费者ACk,接收到ACK后才删除消息,如果没有接收到ACK消息会一直保留在服务端,如果消费者断开连接或异常后,消息会投递给其它消费者。
  • 消费者处理完消息,提交事务后,手动ACK。如果执行过程中抛出异常,则不会ACK,业务处理失败,等待下一条消息

经过上面的两种确认机制,可以确保从消息生产者到消费者的消息安全,再结合生产者和消费者两端的本地事务,即可宝成一个分布式事务的最终一致性。

消息事务的优缺点

  • 优点:
  • 事务相对简单,不需要编写三个阶段业务
  • 是多个本地事务的结合,因此资源锁定周期短,性能好
  • 缺点:
  • 代码侵入
  • 依赖于MQ的可靠性
  • 消息发起者可以回滚,但是消息参与者无法引起事务回滚
  • 事务失效性差,取决于MQ消息发送是否技师,还有消息参与者的执行情况

AT模式解决分布式事务方式

Seata开源了AT模式。AT模式是一种无侵入的分布式事务解决方案。可以看做是对TCC或者二阶段提交模型的一种优化,解决了TCC模式中的代码侵入、编码复杂等问题。

在AT模式下,用户只需关注自己的“业务sql”,用户的“业务sql”作为一阶段,Seata框架会自动生成事务的二阶段提交和回滚操作。

基本原理


mysql执行undo文件 mysql中undo和redo_mysql_12


跟TCC的执行相似,都是分两个阶段

  • 一阶段,执行本地事务,并返回结果
  • 二阶段,根据一阶段的结果,判断二阶段做法:提交或回滚

但AT模式底层做的事情可完全不同,而且第二阶段根本不需要我们编写,全部有Seata自己实现。其实就是我们写的代码与本地事务时代码一样,无需手动处理分布式事务。

AT模式实现原理

  • 第一阶段

Seata会拦截“业务sql”,首先解析SQL语义,找到“业务SQL”要更新的业务数据,在业务数据被更新前,将其保存成“before image”,然后执行“业务SQL”更新业务数据,在业务数据更新之后,再将其保存成“after image”,最后获取全局行锁,提交事务。以上操作都在一个数据库事务内完成,保证了一阶段操作的原子性。

这里的before image和after image类似于数据库的undo和redo日志,但其实是用数据库模拟的。


mysql执行undo文件 mysql中undo和redo_java_13


  • 第二阶段
  • 二阶段提交

二阶段如果是提交的话,因为“业务SQL”在一阶段已经提交至数据库,所以Seata框架只需将一阶段保存的快照数据和行锁删掉,完成数据清理即可。

  • 二阶段回滚

二阶段如果是回滚的话,Seata就需要回滚一阶段已经执行的“业务SQl”,还原业务数据。回滚方式便是用“before image”还原业务数据;但在还原前要首先要校验脏写,对比“数据库当前业务数据”和“after image”,如果两份数据完全一致就说明没有脏写,可以还原数据,如果不一致就说明有脏写,出现脏写就需要转人工处理。


mysql执行undo文件 mysql中undo和redo_mysql_14


因为有全局锁机制,所以可以降低出现脏写的概率。

AT模式的一阶段、二阶段提交和回滚均有Seata框架自动生成,用户只需编写“业务SQL”,便能轻松接入分布式事务,AT模式是一种对业务无任何侵入的分布式事务解决方案。

详细架构和流程

Seata中的几个基本概念:

  • TC(Transaction Coordinator) 事务协调者:

维护全局和分支事务的状态,驱动全局事务提交或回滚(TM之间的协调者)

  • TM(Transaction Manager) 事务管理器

定义全局事务的范围:开始全局事务、提交或回滚全局事务。

  • RM(Resource Manager)资源管理器

管理分支事务处理资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。

Seata架构图如下


mysql执行undo文件 mysql中undo和redo_mysql_15


  • TM:业务模块中全局事务的开启者
  • 向TC开启一个全局事务
  • 调用其它微服务
  • RM:业务模块执行者中,包含RM部分,负责向TC汇报事务执行状态
  • 执行本地事务
  • 向TC注册分支事务,并提交本地事务执行结果
  • TM:结束对微服务的调用,通知TC,全局事务执行完毕,事务一阶段结束
  • TC:汇总各个分支事务执行结果,决定分布式事务是提交还是回滚
  • TC:通知所有RM提交/回滚资源,事务二阶段结束。

第一阶段:

  • TM开启全局事务,并向TC声明全局事务,包括全局事务XID信息
  • TM所在服务调用其它微服务
  • 微服务,主要有RM来执行
  • 查询before_image
  • 执行本地事务
  • 查询after_image
  • 生成undo log 并写入数据库
  • 向TC注册分支事务,告知事务执行结果
  • 获取全局锁(阻止其它全局事务并发修改当前数据)
  • 释放本地锁(不影响其他业务对数据的操作)
  • 待所有执行完毕,事务发起者(TM)会尝试向TC提交全局事务

第二阶段:

  • TC统计分支事务执行情况,根据结果判断下一步行为
  • 分支都成功:通知分支事务,提交事务
  • 有分支执行失败:通知执行成功的分支事务,回滚数据
  • 分支事务的RM
  • 提交事务:直接情况before image和 after image信息,释放全局锁
  • 回滚事务:
  • 校验after image,判断是否有脏写
  • 如果没有脏写,回滚数据到before image,清除before image和after image
  • 如果有脏写,请求人工介入

springcloud部署seata

搭建一个TC服务

下载Seata的jar包

seata压缩包下载


mysql执行undo文件 mysql中undo和redo_mysql_16


配置

在下载好的压缩包解压后


mysql执行undo文件 mysql中undo和redo_mysql_17


在config文件中配置application.yml,可以参考application.example.yml文件进行配置,不要直接覆盖

配置如下:

#  Copyright 1999-2019 Seata.io Group.
#
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#  http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.

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
#1.5.0 版本开始提供了管理后台的web页面,此处配置web的用户名和密码
console:
  user:
    username: seata
    password: seata

seata:
  config:
    # support: nacos, consul, apollo, zk, etcd3
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848
      namespace:
      group: SEATA_GROUP
      username: nacos
      password: nacos
#   nacos配置文件 data-id ,可以用yml(官方给的config.txt是properties,直接用就好)
      data-id: seataServer.properties
  registry:
    # support: nacos, eureka, redis, zk, consul, etcd3, sofa
    type: nacos
    preferred-networks: 30.240.*
    nacos:
      application: seata-server
      server-addr: 127.0.0.1:8848
      group: SEATA_GROUP
      namespace:
# 集群名称,注意需要和事务分组值保持一致
      cluster: default
      username: nacos
      password: nacos
# store 的相关配置在官方部署文档里是在此yml中配置,也可以在 seataServer.properties 中配置
#  store:
    # support: file 、 db 、 redis
   # mode: file
#  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

在nacos中配置store

namespace: public

group: SEATA_GROUP 分组要和上面配置中的一样

Data ID: seataServer.properties 这个和yml文件中的data_id保持一致


mysql执行undo文件 mysql中undo和redo_mysql执行undo文件_18


# 存储模式
store.mode=db
 
store.db.datasource=druid
store.db.dbType=mysql
# 需要根据mysql的版本调整driverClassName
# mysql8及以上版本对应的driver:com.mysql.cj.jdbc.Driver
# mysql8以下版本的driver:com.mysql.jdbc.Driver
store.db.driverClassName=com.mysql.cj.jdbc.Driver
# 注意根据生产实际情况调整参数host和port
store.db.url=jdbc:mysql://127.0.0.1:3306/testseata?rewriteBatchedStatements=true&useUnicode=true&characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useSSL=false
# 数据库用户名
store.db.user=root
# 用户名密码
store.db.password=
# 微服务里配置与这里一致  值 default:集群名称,和 application.yml中 seata.registry.
#nacos.cluster=default 中 default 保持对应
service.vgroupMapping.order_tx_group=default
service.vgroupMapping.storage_tx_group=default
service.vgroupMapping.account_tx_group=default
# global_table、branch_table、distributed_lock、lock_table 四张表需要手动创建
store.db.globalTable=global_table
store.db.branchTable=branch_table
store.db.distributedLockTable=distributed_lock
store.db.lockTable=lock_table

新建数据库

数据库名称和上述配置的一样,根据下面路径找到SQL语句手动创建(global_table、branch_table、distributed_lock、lock_table)

${seata}\script\server\db\mysql.sql

部署完成后启动seata

先启动nacos,在启动seata


mysql执行undo文件 mysql中undo和redo_java_19


有此服务证明配置成功,访问页面即可,根据localhost:7091(ip我是本地配置所以用localhost就可以)可以进入seata页面,账户密码就是application.yml中配置的seata/seata

登录页面


mysql执行undo文件 mysql中undo和redo_java_20


登录后


mysql执行undo文件 mysql中undo和redo_java_21


搭建client 测试

搭建springcloud框架,分为账户,余额,订单三个模块

三个模块分别导入seata jar包

防止cloud版本和seata版本不一致,排除spring自带的seata版本,引入和seata对应的版本
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
            <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.6.1</version>
        </dependency>

account-server的yml文件配置,三个模块配置都大致一样,这里展示两个供参考

server:
  port: 8081
spring:
  datasource:
    druid:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql:///testseata?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
      username: root
      password:
      db-type: com.alibaba.druid.pool.DruidDataSource
      # 初始化配置
      initial-size: 3
      # 最小连接数
      min-idle: 3
      # 最大连接数
      max-active: 15
      # 获取连接超时时间
      max-wait: 5000
#     设置 break-after-acquire-failure 为 true。设置之后数据库连接不成功也不会不断的重试。
#         如果要设置重连次数要设置 connection-error-retry-attempts
      break-after-acquire-failure: true
      connection-error-retry-attempts: 3
        # 配置间隔多久进行一次检测,检测需要关闭的空闲连接,单位毫秒。 默认是60s,太长可能会导致无法及时检测到连接中断。
      time-between-eviction-runs-millis: 90000
        # 配置一个连接在连接池中的最小生存时间、最大生存时间,超过最大生存时间会被移除,单位毫秒。
      min-evictable-idle-time-millis: 1800000
#       配置从连接池获取连接时,当连接空闲时间大于timeBetweenEvictionRunsMillis时是否检查连接有效性,true每次都检查;false不检查。
      test-while-idle: true
#        配置从连接池获取连接时和向连接池归还连接时,是否检查连接有效性。
#   每次获取或归还连接都检测太频繁,除非特别重要或网络特别不可靠等情况,建议用testWhileIdle + timeBetweenEvictionRunsMillis代替。
      test-on-borrow: false
      test-on-return: false
#        探活、验证链接有效性的查询,新版本默认使用mysqlPing代替
      validation-query: select 1
        # 配置监控统计拦截的filters  StatFilter的别名是stat,配置stat表示开启SQL监控  配置wall:开启SQL防火墙
      filters: stat
#        配置 Druid 监控信息显示页面
      stat-view-servlet:
#          访问地址规则
        url-pattern: /druid/*
#          是否允许清空统计数据,false:不允许,true:允许
        reset-enable: false
#          监控页面的用户,密码
        login-username: admin
        login-password: admin
#          设置白名单(如果allow没有配置或者为空,表示允许所有访问)
#          黑名单(注意 deny 的优先级高于 allow,即只有在 deny 列表中,那么即使在 allow 列表中,也会被拒绝)
        allow: 127.0.0.1
        enabled: true   #默认值为true,即打开监控页面,但存在泄漏信息的风险,所以修改为false
      web-stat-filter:
#          匹配的url
        url-pattern: /*
#          排除一些不必要的url,比如.js,/jslib/等等
        exclusions: "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*"
  application:
    name: account-server
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
        group: SEATA_GROUP
seata:
#这里每个服务都是对应不同的映射名,在配置中心可以看到
  tx-service-group: account_tx_group
  registry:
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848
      group: SEATA_GROUP
  service:
    vgroup-mapping:
#     这里的key为映射名
      account_tx_group: default
logging:
  level:
    com.seata.mapper: debug
    io:
      seata: info

order-server的yml文件

server:
  port: 8082
spring:
  datasource:
    druid:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql:///testseata?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
      username: root
      password:
      db-type: com.alibaba.druid.pool.DruidDataSource
      # 初始化配置
      initial-size: 3
      # 最小连接数
      min-idle: 3
      # 最大连接数
      max-active: 15
      # 获取连接超时时间
      max-wait: 5000
      #     设置 break-after-acquire-failure 为 true。设置之后数据库连接不成功也不会不断的重试。
      #         如果要设置重连次数要设置 connection-error-retry-attempts
      break-after-acquire-failure: true
      connection-error-retry-attempts: 3
      # 配置间隔多久进行一次检测,检测需要关闭的空闲连接,单位毫秒。 默认是60s,太长可能会导致无法及时检测到连接中断。
      time-between-eviction-runs-millis: 90000
      # 配置一个连接在连接池中的最小生存时间、最大生存时间,超过最大生存时间会被移除,单位毫秒。
      min-evictable-idle-time-millis: 1800000
      #       配置从连接池获取连接时,当连接空闲时间大于timeBetweenEvictionRunsMillis时是否检查连接有效性,true每次都检查;false不检查。
      test-while-idle: true
      #        配置从连接池获取连接时和向连接池归还连接时,是否检查连接有效性。
      #   每次获取或归还连接都检测太频繁,除非特别重要或网络特别不可靠等情况,建议用testWhileIdle + timeBetweenEvictionRunsMillis代替。
      test-on-borrow: false
      test-on-return: false
      #        探活、验证链接有效性的查询,新版本默认使用mysqlPing代替
      validation-query: select 1
      # 配置监控统计拦截的filters  StatFilter的别名是stat,配置stat表示开启SQL监控  配置wall:开启SQL防火墙
      filters: stat
      #        配置 Druid 监控信息显示页面
      stat-view-servlet:
        #          访问地址规则
        url-pattern: /druid/*
        #          是否允许清空统计数据,false:不允许,true:允许
        reset-enable: false
        #          监控页面的用户,密码
        login-username: admin
        login-password: admin
        #          设置白名单(如果allow没有配置或者为空,表示允许所有访问)
        #          黑名单(注意 deny 的优先级高于 allow,即只有在 deny 列表中,那么即使在 allow 列表中,也会被拒绝)
        allow: 127.0.0.1
        enabled: true   #默认值为true,即打开监控页面,但存在泄漏信息的风险,所以修改为false
      web-stat-filter:
        #          匹配的url
        url-pattern: /*
        #          排除一些不必要的url,比如.js,/jslib/等等
        exclusions: "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*"
  application:
    name: order-server
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
        group: SEATA_GROUP
#feign:
#  client:
#    config:
#      # 提供方的服务名
#      account-server:
#        #请求日志级别
#        loggerLevel: BASIC
#        contract: feign.Contract.Default #设置为默认的契约(还原成原生注解)
#        # 连接超时时间,默认2s,设置单位为毫秒
#        connectTimeout: 5000
#        # 请求处理超时时间,默认5s,设置单位为毫秒。
feign:
  httpclient:
    connection-timeout:
        readTimeout: 3000
  client:
    default-config: default
seata:
  tx-service-group: order_tx_group
  registry:
    type: nacos
    nacos:
      server-addr: localhost:8848
      group: SEATA_GROUP
#  值 default:集群名称,和 seata配置文件中application.yml中 seata.registry.nacos.cluster=default 中 default 保持对应
  service:
    vgroup-mapping:
      order_tx_group: default
logging:
  level:
    com.seata.mapper: debug
    io:
      seata: info