一、分布式事务基础
1. 事务
要学习分布式事务,首先要了解什么是事务:事务就是在某些业务场景下,需要在数据库中执行的一组相关SQL语句或操作,作为一个不可再分的逻辑单元这些SQL语句或操作要么全部执行成功,要么全部执行失败。如经典的事务场景——转账:假设使用数据库描述张三给李四转账100元这件事,从数据库的角度看就是张三的账户减去100李四的账户加上100,这两条对数据库更新的SQL语句就必须全部执行成功(即转账成功),或者全部执行失败(即转账失败)。
2. 事务的特征
事务具有四个特征:原子性(atomicity)、一致性(consistency)、隔离性(isolation)、持久性(durability),简称ACID。
- 原子性
- 作为一个原子单元,事务中的所有SQL语句或操作不可再分,只能被全部执行成功或者全部执行失败,不能只执行部分SQL语甸或操作。例如,上面转账案例中张三账户-100和李四账户+100必须是同时执行的,不能只执行一部分。
- 一致性
- 事务执行前后数据库的状态是一致的,例如,转账之前张三账户有100,李四账户有100,加起来是200,转账之后张三账户为0,而李四账户为200,总数还是200,事务执行前后数据的状态是一致的。
- 隔离性
- 隔离性指的是多个事务操作同一张表时,相互之间影响的程度。例如,张三给李四转账的同时,其他人也正在给李四转账,或者李四在给别人转账,存在多个事务在同时操作相同数据,可能会因此出现一些问题。
- 持久性
- 持久性是指一个事务一旦被提交了,那么对数据库中数据的改变就是永久性的,即便数据库系统在遇到故障的情况下也不会丢失提交事务的操作。
3. 本地事务
在传统的单体应用中,一般服务器使用的是本地的数据库(数据库被安装在服务器本地),而且在业务逻辑实现的过程中如果需要使用事务的场景,那么只需要操作服务器本地的数据库,不需要远程过程调用(remote procedure cal,RPC)其他的数据库服务器.这种事务被称为本地事务。
在 Spring中,处理本地事务一般使用@Transactional注解,本质上也是采用数据库支持的事务性实现的。
4.分布式事务
分布式事务是与本地事务相对的概念,如果事务单元需要操作来自不同数据源的数据或既有本地数据源的操作也有远程过程调用其他服务完成本次业务,那么这就需要使务用分布式事务。所以分布式事务就是保证操作不同数据源的数据一致性问题。
二、分布事务的理论基础
1.CAP理论
CAP理论是分布式系统设计中的一个核心原理,由Eric Brewer在2000年提出,并在2002年被Seth Gilbert和Nancy Lynch证明。CAP代表了三个关键属性:
- 一致性(Consistency): 在分布式系统中的所有节点上,对数据的访问看起来就像是访问了一个单一的、一致性的数据源。这意味着,如果一个写操作成功完成,那么所有后续的读操作都应该能够立刻看到这个更新的结果。简而言之,所有节点上的数据副本需要保持同步。
- 可用性(Availability): 指的是系统能够持续处理请求并给出响应的能力,无论这些请求是否能获取到最新或最准确的数据。也就是说,每一个请求都会收到一个响应,尽管在某些情况下响应可能是旧数据或者是错误信息。
- 分区容错性(Partition Tolerance): 分布式系统在网络分区(即系统中的部分节点无法与其他节点通信)的情况下,仍然能够对外提供服务。在实际的分布式环境中,由于网络问题,分区几乎是不可避免的。
CAP理论指出,在一个分布式系统中,设计时不可能同时达到这三个属性的最优状态。设计者必须在这三个特性之间做出权衡,通常只能满足其中的两个。具体选择哪两个特性取决于系统的具体需求:
- CA系统:如果放弃P,即假设没有网络分区的情况,系统可以同时满足一致性和可用性。但在实际网络环境中,这通常是不现实的。
- CP系统:在发生网络分区时,优先保证一致性和分区容错性,牺牲可用性。这样的系统在面对分区时可能会拒绝一部分读写操作,以确保数据的一致性。
- AP系统:优先保证可用性和分区容错性,牺牲一致性。在这种系统中,即使在分区情况下,每个请求也都会收到响应,但返回的数据可能不是最新的。
因此,理解CAP理论有助于架构师在设计分布式系统时做出合理的选择,以适应特定的应用场景和业务需求。
2.BASE理论
BASE理论是针对大型分布式系统设计中,特别是在考虑数据一致性与系统可用性之间的权衡时,提出的一种理论模型。它是对CAP理论中一致性和可用性权衡结果的进一步发展,尤其是在舍弃强一致性而追求高可用性场景下的实践原则。BASE理论主要包括三个核心元素:
一、基本可用(Basically Available):
这意味着在分布式系统中,即使部分组件出现故障,系统也应尽可能地继续提供服务。尽管可能不是所有功能都能正常工作,但要保证核心功能的可用性。例如,在电商系统中,即使订单处理速度变慢,也要确保用户能够浏览商品和加入购物车。
二、软状态(Soft State):
软状态指的是系统可以接受数据的不一致状态,并将其视为一种临时的、过渡的状态。与传统数据库的“硬状态”(即数据一旦写入就立即一致)不同,软状态允许数据在不同节点间异步复制,因此在某一时刻不同副本间可能存在差异。这种机制提高了系统的响应速度和可用性,因为系统不需要等待所有副本都更新完毕就能响应请求。
三、最终一致性(Eventual Consistency):
最终一致性是BASE理论的最终目标,它要求系统中的所有数据副本,在经过一段时间和一系列数据同步操作后,最终能够达到一致的状态。这并不保证每次读取都能获取到最新写入的数据,而是说系统需要有一种机制确保数据最终能够达成一致,这可能需要几秒到几分钟的时间。
BASE理论适用于那些需要高度可用性并且能够容忍一定程度数据不一致性的场景,如大型电子商务网站、社交网络等。与ACID(原子性、一致性、隔离性、持久性)事务模型相比,BASE理论提供了在分布式环境下的另一种事务处理哲学,更侧重于系统的扩展性和灵活性。
3.X/Open分布式事务处理模型
X/Open分布式事务处理(X/Open distributed transaction processing reference, X/Open DTP)模型是X/Open定义的一套分布式事务标准。这个标准提出了两阶段提交以保证分布式事务的完整性。
X/Open DTP模型中的角色:
1、AP(Application Program)
AP即应用程序,主要是定义事务边界及那些组成事务的特定于应用程序的操作,可以将之理解为使用DTP的程序。
2、RM(Resouces Manager)
RM即资源管理器,管理一些共享资源的自治域,如提供对诸如数据库之类的共享资源的访问。这里可以将之理解为一个DBMS,或者说消息服务器管理系统,应用程序通过资源管理器对资源进行控制,而资源必须实现XA定义的接口。
3、TM(Transaction Manager)
TM即事务管理器,管理全局事务,协调事务的提交或者回滚,并协调故障恢复,提供给应用程序编程接口及管理资源管理器,其可以被理解为Spring中提供的事务管理器
三、seata叙述
Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。
四、Seata支持的事务模型
1)Seata事务管理中有三个重要的角色
- TC (Transaction Coordinator) - 事务协调者:维护全局和分支事务的状态,协调全局事务提交或回滚。
- TM (Transaction Manager) - 事务管理器:定义全局事务的范围、开始全局事务、提交或回滚全局事务。
- RM (Resource Manager) - 资源管理器:管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。
2)各事务模式
Seata提供了四种不同的分布式事务解决方案:AT模式、XA模式、TCC模式、SAGA模式
(1) XA模式:强一致性分阶段事务模式,牺牲了一定的可用性,无业务侵入
(2) TCC模式:最终一致的分阶段事务模式,有业务侵入
(3) AT模式:最终一致的分阶段事务模式,无业务侵入,也是Seata的默认模式
(4) SAGA模式:长事务模式,有业务侵入
具体概述可以访问seata官网查看:点此查看
五、Seata快速开始
1.Seata Server(TC)环境搭建
1)下载seata
下载地址:https://seata.apache.org/zh-cn/unversioned/release-history/seata-server
本文采用seata-server-1.7.0部署为例
2)事务信息配置,创建数据库
Server 端存储模式(store.mode)本文采用db模式
5.2.1 创建名为seata的数据库
位置在seata\script\server\db\mysql.sql的sql文件,以下为sql文件的代码:
-- -------------------------------- 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);
5.2.2 配置server端的application.yml文件
文件位置:\seata\conf\application.yml,在同文件下有一个application.example.yml的文件我们可以对照他进行server端的配置。
application.yml:
application.example.yml:
打开application.yml文件,在本文档使用nacos作为配置中心,选用db模式。
修改seata的属性config、registry的type以及属性store的db,将config、registry的type属性修改成nacos,store的属性mode修改成db
- 增加config的属性nacos如下述配置:
nacos: server-addr: 127.0.0.1:8848 namespace: group: SEATA_GROUP username: nacos password: nacos data-id: seataServer.properties
- 增加registry属性nacos如下配置:
nacos: application: seata-server server-addr: 127.0.0.1:8848 group: DEFAULT_GROUP namespace: cluster: default #这里的集群名要跟接下来的nacos中的配置一致 username: nacos password: nacos
- 增加store的属性db,如下配置:
db: datasource: druid db-type: mysql driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/seata?rewriteBatchedStatements=true user: root password: 123456 min-conn: 10 max-conn: 100 global-table: global_table branch-table: branch_table lock-table: lock_table distributed-lock-table: distributed_lock query-limit: 1000 max-wait: 5000
具体的要添加的属性在前文提及的application.example.yml有参考
完成后:
3)Nacos配置:
启动nacos,添加配置,注意要dataid要与前边步骤server端的yml中config中设置的名称和组别一致。
Data ID: seataServer.properties
GROUP:SEATA_GROUP
配置格式选择Properties
在seata文件里有对应的代码(需自己修改):seata\script\config-center\ config.txt。将txt文件中的代码修改后粘入到当前新建配置中。
需要修改的属性:
- 配置事务分组:
service.vgroupMapping.default_tx_group=default
my_test_tx_group:需要与客户端保持一致 ,可以自定义
(在后续客户端application.yml配置:seata的属性中事务组名称、和集群名称要跟server端的application.yml中已经设置好的一致)
default:需要跟客户端和application.yml中seata属性registry中的cluster保持一致 (即5.2.2的配置)
default 必须要等于 registry.conf cluster = “default”
- 修改数据库相关配置:
store.mode=file #改成db
store.lock.mode=file #改成db
store.session.mode=file #改成db
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.jdbc.Driver #这里改成com.mysql.cj.jdbc.Driver
store.db.url=jdbc:mysql://127.0.0.1:3306/seatauseUnicode=true&rewriteBatchedStatements=true #改成自己数据库的路径
store.db.user=username #这里改成自己的用户名
store.db.password=password #这里改成自己的密码
- 将file、redis的配置删掉:
#If `store.mode,store.lock.mode,store.session.mode` are not equal to `file`, you can remove the configuration block.
store.file.dir=file_store/data
store.file.maxBranchSessionSize=16384
store.file.maxGlobalSessionSize=512
store.file.fileWriteBufferCacheSize=16384
store.file.flushDiskMode=async
store.file.sessionReloadReadSize=100
#These configurations are required if the `store mode` is `redis`. If `store.mode,store.lock.mode,store.session.mode` are not equal to `redis`, you can remove the configuration block.
store.redis.mode=single
store.redis.single.host=127.0.0.1
store.redis.single.port=6379
store.redis.sentinel.masterName=
store.redis.sentinel.sentinelHosts=
store.redis.maxConn=10
store.redis.minConn=1
store.redis.maxTotal=100
store.redis.database=0
store.redis.password=
store.redis.queryLimit=100
4)启动运行
六、SEATA模式AT事例简单运行
这里采用的代码是黑马程序员在b站发布的视频的代码,视频链接地址:黑马Seata入门到实战教程,快速学习Seata分布式解决方案,XA模式 TCC模式 AT模式 Saga模式_哔哩哔哩_bilibili
1)父pom设置:
Seata和SpringCloud及SpringCloudAlibaba对应版本查询地址: 点此查看
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.itcast.demo</groupId>
<artifactId>seata-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<modules>
<module>storage-service</module>
<module>account-service</module>
<module>order-service</module>
</modules>
<packaging>pom</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.2</version>
<relativePath/>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>17</java.version>
<spring-cloud.version>2022.0.0</spring-cloud.version>
<mybatis.plus.version>3.5.6</mybatis.plus.version>
<mysql.version>8.0.28</mysql.version>
<alibaba.version>2022.0.0.0</alibaba.version>
<seata.version>1.7.0</seata.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- springCloud -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis.plus.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--单元测试-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
2)各个服务pom设置
- account-service
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>seata-demo</artifactId> <groupId>cn.itcast.demo</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>account-service</artifactId> <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>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>3.0.3</version> </dependency> <!--seata--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-seata</artifactId> <exclusions> <exclusion> <artifactId>seata-spring-boot-starter</artifactId> <groupId>io.seata</groupId> </exclusion> </exclusions> </dependency> <dependency> <groupId>io.seata</groupId> <artifactId>seata-spring-boot-starter</artifactId> <version>${seata.version}</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
- Order-service
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>seata-demo</artifactId> <groupId>cn.itcast.demo</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>order-service</artifactId> <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>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>3.0.3</version> </dependency> <!--seata--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-seata</artifactId> <exclusions> <exclusion> <artifactId>seata-spring-boot-starter</artifactId> <groupId>io.seata</groupId> </exclusion> </exclusions> </dependency> <dependency> <groupId>io.seata</groupId> <artifactId>seata-spring-boot-starter</artifactId> <version>${seata.version}</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
- Storage-service:
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>seata-demo</artifactId> <groupId>cn.itcast.demo</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>storage-service</artifactId> <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>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>3.0.3</version> </dependency> <!--seata--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-seata</artifactId> <exclusions> <exclusion> <artifactId>seata-spring-boot-starter</artifactId> <groupId>io.seata</groupId> </exclusion> </exclusions> </dependency> <dependency> <groupId>io.seata</groupId> <artifactId>seata-spring-boot-starter</artifactId> <version>${seata.version}</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
3)添加数据库seata-demo
- 在黑马程序员的源码里有对应的sql代码,可以自己寻找去下载 。
- 我们还需要再seata_demo数据库里加入一个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;
4)修改client端每个服务的application.yml
- 配置seata,如下所示:
6.4.1. 配置服务注册中心(registry)
registry: type: nacos nacos: server-addr: 127.0.0.1:8848 namespace: "" group: DEFAULT_GROUP application: seata-server username: nacos password: nacos
- type: 这里我们指定使用
nacos
。- server-addr: 填写Nacos服务器的地址和端口。
- namespace: 可以留空,表示使用默认命名空间。
- group: 指定服务注册的组,通常使用
DEFAULT_GROUP,与之前步骤在server端设置的application.yml中的registry一致
。- application: 填写应用名称,比如
seata-server,与与之前步骤在server端设置的application.yml中的registry一致
。- username和password: 需要使用Nacos的认证信息。
6.4.2 配置事务组名称(tx-service-group)
- 定义事务组名称
tx-service-group: seata-demo
6.4.3 配置服务映射(service)
- 配置虚拟组到实际组的映射关系。
service: vgroup-mapping: seata-demo: default
- vgroup-mapping: 这里配置虚拟组
seata-demo
映射到实际组default
。与在之前步骤的nacos的配置中service.vgroupMapping.default_tx_group=default这一属性对应(可以自己修改事务组名称)
6.4.4 配置数据源代理模式
- 指定数据源代理模式为AT(自动事务)。
data-source-proxy-mode: AT
6.4.5 配置配置中心(config):
- 配置Seata的配置中心为Nacos,并提供Nacos的地址和认证信息。(与之前在server端的application.yml设置一致)
config: type: nacos nacos: server-addr: 127.0.0.1:8848 username: nacos password: nacos group: SEATA_GROUP data-id: seataServer.properties
- type: 这里我们指定使用
nacos
。- server-addr: 填写Nacos服务器的地址和端口。
- username和password: 使用Nacos的认证信息。
- group: 配置在Nacos中的配置组名,比如
SEATA_GROUP
。与之前在Server端的application.yml设置一致- data-id: 指定在Nacos中的配置文件名,比如
seataServer.properties
。与Nacos中的配置名称一致
6.4.6 完整代码
server:
port: 8083
spring:
application:
name: account-service
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/seata_demo?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=false
username: root
password: 123456
cloud:
nacos:
server-addr: localhost:8848
discovery:
username: nacos
password: nacos
mybatis-plus:
global-config:
db-config:
insert-strategy: not_null
update-strategy: not_null
id-type: auto
logging:
level:
org.springframework.cloud.alibaba.seata.web: debug
cn.itcast: debug
pattern:
dateformat: MM-dd HH:mm:ss:SSS
seata:
registry:
type: nacos
nacos:
server-addr: 127.0.0.1:8848
namespace: ""
group: DEFAULT_GROUP
application: seata-server
username: nacos
password: nacos
tx-service-group: seata-demo # 事务组名称
service:
vgroup-mapping:
seata-demo: default
data-source-proxy-mode: AT
config:
type: nacos
nacos:
server-addr: 127.0.0.1:8848
username: nacos
password: nacos
group: SEATA_GROUP
data-id: seataServer.properties
5)运行
运行成功后能发现4个服务
通过apipost调试也能成功