Spring cloud 整合 Seata(At)
Nacos 整合 Seata (At) 模式
Seata官网:https://seata.io/zh-cn/index.html
代码:https://gitee.com/yihong-sword/learn-nacos-cloud.git
下载:
- Seata 服务端 (官网-下载-选择版本-选择binary)
- Seata 源码 (官网-下载-选择版本-选择source)
Seata 命令(Mac):
- 启动:./seata-server.sh
建表
- Server 服务端 (这里创建表结构是需要创建一个新的数据库 比如 seata 后续是需要指定该数据库地址)
- 在已经下好的源码里包含了 server 服务端所需要的表结构,路径为:seata/源码/seata-1.4.2/script/server/db 选择不同数据库.sql 执行即可
- Client 业务端 (也就是代码里实际需要分布式事务的业务库)
- 在已经下好的源码里包含了 server 业务端所需要的表结构,路径为:seata/源码/seata-1.4.2/script/client/at/db 选择不同数据库.sql 执行即可 (需要注意的是:如果一共有3个服务,那么就要在各自的业务库中分别创建该表)
修改server配置(Nacos)
在已经下好源码里,是可以找到这些配置的模板,路径为:seata/源码/seata-1.4.2/script/server/config
file.conf
## transaction log store, only used in seata-server store { ## store mode: file、db、redis mode = "file" ## file store property file { ## store location dir dir = "sessionStore" # branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions maxBranchSessionSize = 16384 # globe session size , if exceeded throws exceptions maxGlobalSessionSize = 512 # file buffer size , if exceeded allocate new buffer fileWriteBufferCacheSize = 16384 # when recover batch read size sessionReloadReadSize = 100 # async, sync flushDiskMode = async } ## database store property db { ## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp)/HikariDataSource(hikari) etc. datasource = "druid" ## mysql/oracle/postgresql/h2/oceanbase etc. dbType = "mysql" driverClassName = "com.mysql.jdbc.Driver" ## 我看网上有修改这个的,我没有修改。但是也好用 url = "jdbc:mysql://127.0.0.1:3306/seata" user = "mysql" password = "mysql" minConn = 5 maxConn = 100 globalTable = "global_table" branchTable = "branch_table" lockTable = "lock_table" queryLimit = 100 maxWait = 5000 } ## redis store property redis { host = "127.0.0.1" port = "6379" password = "" database = "0" minConn = 1 maxConn = 10 queryLimit = 100 } }
registry.conf
registry { # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa type = "nacos" nacos { application = "seata-server" serverAddr = "127.0.0.1:8848" namespace = "" cluster = "default" username = "nacos" password = "nacos" } } config { # file、nacos 、apollo、zk、consul、etcd3 type = "nacos" nacos { serverAddr = "127.0.0.1:8848" namespace = "" group = "SEATA_GROUP" username = "nacos" password = "nacos" } }
application.yml
源码路径为:seata/源码/seata-1.4.2/script/client/spring
事务分组专题(tx-service-group):https://seata.io/zh-cn/docs/user/transaction-group.html
下面代码需要复制到各项目application.yml文件内
seata: enabled: true application-id: provider tx-service-group: my_test_tx_group config: type: nacos nacos: namespace: "" server-addr: 127.0.0.1:8848 group: SEATA_GROUP username: "" password: "" registry: type: nacos nacos: application: seata-server server-addr: 127.0.0.1:8848 group : SEATA_GROUP namespace: "" username: "" password: "" log: exception-rate: 100
Nacos 配置中心
源码里路径为:seata/源码/seata-1.4.2/script/config-center/config.txt
修改完下面配置之后,保存原文件,返回上一层并进入nacos文件夹,执行./nacos-config.sh,此时配置已上传nacos
service.vgroupMapping.my_test_tx_group=default service.disableGlobalTransaction=false store.mode=db store.db.datasource=druid store.db.dbType=mysql
// 下面的驱动是mysql8.0版本 store.db.driverClassName=com.mysql.cj.jdbc.Driver
// 指定的seata 服务端创建的数据库 store.db.url=jdbc:mysql://127.0.0.1:3306/seata_server?useUnicode=true&rewriteBatchedStatements=trueseata?useUnicode=true&rewriteBatchedStatements=true store.db.user=user store.db.password=password store.db.minConn=5 store.db.maxConn=30 store.db.globalTable=global_table store.db.branchTable=branch_table store.db.queryLimit=100 store.db.lockTable=lock_table store.db.maxWait=5000
项目配置(业务代码,我就不多写了,首先AT模式本就对业务代码侵入较少)
- Jdk 14
- Mysql 8.0
- Nacos
- Spring boot 2.4.10
- Seata 2021.1
- io.seata 1.3.0
- Jpa 2.5
- openFeign 3.0.2
Pom
<?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>org.example</groupId> <artifactId>learn_nacos_cloud</artifactId> <packaging>pom</packaging> <version>1.0-SNAPSHOT</version> <modules> <module>provider</module> <module>consumer</module> <module>consumer</module> </modules> <properties> <java.version>1.8</java.version> <spring-boot.version>2.4.10</spring-boot.version> <spring-cloud.version>2020.0.2</spring-cloud.version> <spring-cloud-alibaba.version>2020.0.RC1</spring-cloud-alibaba.version> <alibaba.seata.starter.version>2.2.5.RELEASE</alibaba.seata.starter.version> <lombok.version>1.18.20</lombok.version> <slf4j.version>1.7.25</slf4j.version> <jpa.version>2.5.0</jpa.version> <mysql.version>8.0.13</mysql.version> <spring-cloud-starter-openfeign.version>3.0.2</spring-cloud-starter-openfeign.version> <seata-spring-boot-starter.version>1.4.2</seata-spring-boot-starter.version> <nacos.cloud.starter.version>2.2.6.RC1</nacos.cloud.starter.version> <spring-cloud-starter-loadbalancer.version>3.0.4</spring-cloud-starter-loadbalancer.version> </properties> <dependencyManagement> <dependencies> <!-- spring boot 依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!-- spring cloud 依赖 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!-- spring cloud alibaba 依赖 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>${spring-cloud-alibaba.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!--nacos 注册中心服务发现--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <version>${nacos.cloud.starter.version}</version> </dependency> <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${slf4j.version}</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-jpa --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> <version>${jpa.version}</version> </dependency> <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-seata</artifactId> <version>LATEST</version> <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.3.0</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> <version>${spring-cloud-starter-openfeign.version}</version> <scope>compile</scope> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-loadbalancer --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</artifactId> <version>${spring-cloud-starter-loadbalancer.version}</version> </dependency> <!-- hystrix--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> <version>2.2.8.RELEASE</version> </dependency> </dependencies> </dependencyManagement> </project>
子项目 pom
<?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> <parent> <artifactId>learn_nacos_cloud</artifactId> <groupId>org.example</groupId> <version>1.0-SNAPSHOT</version> </parent> <name>provider</name> <groupId>org.example</groupId> <artifactId>provider</artifactId> <version>${parent.version}</version> <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-seata</artifactId> </dependency> <dependency> <groupId>io.seata</groupId> <artifactId>seata-spring-boot-starter</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.12.0</version> </dependency> <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-jpa --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> </dependencies> <properties> <maven.compiler.source>14</maven.compiler.source> <maven.compiler.target>14</maven.compiler.target> </properties> </project>
项目目录:
Seata At模式理解
官方讲解(完全可以轻易看懂):https://seata.io/zh-cn/docs/overview/what-is-seata.html
首先Seata 术语
-
TC (Transaction Coordinator) - 事务协调者
维护全局和分支事务的状态,驱动全局事务提交或回滚。
-
TM (Transaction Manager) - 事务管理器
定义全局事务的范围:开始全局事务、提交或回滚全局事务。
-
RM (Resource Manager) - 资源管理器
管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。
工作原理简单说就是:在服务代码获取本地锁之后,在业务库undo_log 会生成一条记录,列:rollback_info 储存是一个json,保存的是该sql 执行前 以及执行后,
- 事务回滚,会分析执行前是什么样的数据 ,并且拼装好sql执行,并且删除该记录
- 正常执行,则直接删除掉该记录
异常及解决办法
- Seata 和 OpenFeign 冲突 Error creating bean with name 'seataFeignObjectWrapper' defined in class path resource 这个错误就是版本不兼容。换成文档里的版本就不会有这个错了(我调试这个错误接近2个礼拜。。看了无数帖子 挨个试。。)
- A component required a bean of type 'org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient' that could not be found. 这个比较有意思它的意思是缺失,但是由于之前我引用了 loadbalancer jar 也看过确实引入该class 所以就很迷惑,把该jar 引用给去掉就完事了。这个错就消失了
启动顺序
- Nacos
- Seata
- 项目