背景
在前面的文章中,我们已经讲解了如何搭建Seata server1.5.2版本,接下来我们要使用搭建好的Seata server来真正集成分布式事务到我们的spring cloud项目当中。
我们在接下来的项目中,将以电商网站下单功能作为示例来讲述如何集成Seata AT模式。
1.用户下单请求进入Business
业务入口,也就是我们的TM,TM立马与TC请求开启全局事务,拿到XID;
2.TM拿到XID后,依次通过RPC并携带XID去调用
钱包扣款
、创建订单
;
- 在接收到远程调用时,RM获取XID,并执行业务逻辑(对应扣款、创建订单),同时生成undo_log(seata的undo_log)记录,此时分支事务还未提交,此刻RM向TC注册分支事务,并产生行锁,注册成功后,将提交分支事务;后续如果需要回滚,将根据undo_log回滚;
3.创建订单的过程中,又需要通过RPC调用实现
扣减库存
的操作;操作流程与第2步一样;4.在所有服务都调用完毕正常返回后,TM发起全局事务提交动作;或者在其中任意服务调用失败后TM发起全局事务回滚动作;
5.TC收到全局事务提交或回滚请求后,依次通知所有分支事务提交或回滚,以便达到分布式事务提交或回滚的目的;
注意:在seata中,是允许TM和RM放在一个服务当中的,当前示例把TM和RM拆开来演示能够更加清晰地阐述TM和RM各自的功能,真实开发或生产环境中,开发人员可灵活使用。
项目结构
1.awesome-business
是整个项目的入口,该服务与前端直接交互,为前端提供服务接口;
2.
awesome-account
是钱包功能所在的服务,包含钱包扣款功能;3.
awesome-order
包含创建订单的功能;4.
awesome-storage
包含扣减库存的功能;5.
account-api
、order-api
、storage-api
的作用是暴露接口给awesome-business
使用,做一个接口桥接的作用。
依赖
awesome-business
作为TM,并同时对前端提供API,需要的功能包括spring mvc
、服务发现
、RPC调用
、seata分布式事务
等,所以对应的依赖如下:
<?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.7.3</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>awesome-business</artifactId> <version>0.0.1-SNAPSHOT</version> <name>awesome-business</name> <description>awesome-business</description> <properties> <java.version>11</java.version> <spring-cloud.version>2021.0.4</spring-cloud.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <!-- spring mvc功能--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <!-- 服务发现--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <version>2021.0.4.0</version> </dependency> <!-- RPC调用工具--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> <version>3.1.4</version> </dependency> <!-- 替换默认的URLConnection,改为okhttp,并添加链接池--> <dependency> <groupId>io.github.openfeign</groupId> <artifactId>feign-okhttp</artifactId> <version>11.9.1</version> </dependency> <!-- openFeign负载均衡由ribbon改为loadbalancer--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-loadbalancer</artifactId> <version>3.1.4</version> </dependency> <!-- 解决项目启动警告:LoadBalancerCacheManager not available, returning delegate without caching.--> <!-- 如果注册中心有自己的缓存,那么就可以禁用loadbalancer的缓存--> <dependency> <groupId>com.github.ben-manes.caffeine</groupId> <artifactId>caffeine</artifactId> <version>3.1.1</version> </dependency> <!-- 解决项目启动警告:Spring Cloud LoadBalancer is currently working with the default cache. You can switch to using Caffeine cache, by adding it and org.springframework.cache.caffeine.CaffeineCacheManager to the classpath.--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> </dependency> <!-- 分布式事务框架Seata --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-seata</artifactId> <version>2021.0.4.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.12.0</version> </dependency> <!-- account服务暴露接口--> <dependency> <groupId>com.example</groupId> <artifactId>account-api</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> <!-- order服务暴露接口--> <dependency> <groupId>com.example</groupId> <artifactId>order-api</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build> </project> 复制代码
awesome-account
、awesome-order
、awesome-storage
作为RM,同时向awesome-business
暴露接口,需要数据库操作
、spring mvc
、seata分布式事务
等功能,可能也需要RPC调用
,所以对应的依赖如下:
<?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.7.3</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <!-- 记得替换artifactId --> <artifactId>awesome-order</artifactId> <version>0.0.1-SNAPSHOT</version> <name>awesome-order</name> <description>awesome-order</description> <properties> <java.version>11</java.version> <spring-cloud.version>2021.0.4</spring-cloud.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- spring mvc功能 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <!--nacos注册中心--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <version>2021.0.4.0</version> </dependency> <!-- RPC调用工具 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> <version>3.1.4</version> </dependency> <!-- 替换默认的URLConnection,改为okhttp,并添加链接池--> <dependency> <groupId>io.github.openfeign</groupId> <artifactId>feign-okhttp</artifactId> <version>11.9.1</version> </dependency> <!-- openFeign负载均衡由ribbon改为loadbalancer--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-loadbalancer</artifactId> <version>3.1.4</version> </dependency> <!-- 解决项目启动警告:LoadBalancerCacheManager not available, returning delegate without caching.--> <!-- 如果注册中心有自己的缓存,那么就可以禁用loadbalancer的缓存--> <dependency> <groupId>com.github.ben-manes.caffeine</groupId> <artifactId>caffeine</artifactId> <version>3.1.1</version> </dependency> <!-- 解决项目启动警告:Spring Cloud LoadBalancer is currently working with the default cache. You can switch to using Caffeine cache, by adding it and org.springframework.cache.caffeine.CaffeineCacheManager to the classpath.--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> </dependency> <!--seata分布式事务框架--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-seata</artifactId> <version>2021.0.4.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- 【数据库】mysql driver --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.30</version> </dependency> <!--【数据库】数据库连接池--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.11</version> </dependency> <!--【数据库】持久层框架 mybatis--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.2.2</version> </dependency> <!--【数据库】分页插件--> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>1.4.3</version> </dependency> <!-- order服务自己的接口 --> <dependency> <groupId>com.example</groupId> <artifactId>order-api</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> <!-- storage服务暴露的接口 --> <dependency> <groupId>com.example</groupId> <artifactId>storage-api</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> </dependencies> <build> <resources> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> <include>**/*.yml</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> </resources> <plugins> <!-- mybatis-generator maven插件,用于生成DAO代码 --> <plugin> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-maven-plugin</artifactId> <version>1.4.1</version> <configuration> <verbose>true</verbose> <overwrite>true</overwrite> <!-- mybatis-generator配置文件路径 --> <configurationFile>${basedir}/src/main/resources/mybatis/generator/generatorConfig.xml </configurationFile> </configuration> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build> </project> 复制代码
以上是awesome-order
服务对应的依赖,awesome-account
、awesome-storage
可参照上面的依赖按需修改,awesome-account
、awesome-storage
因为不需要RPC调用
,可删除对应的RPC调用
依赖及其相关的优化关联的依赖,也就是以下这一段:
<!-- RPC调用工具 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> <version>3.1.4</version> </dependency> <!-- 替换默认的URLConnection,改为okhttp,并添加链接池--> <dependency> <groupId>io.github.openfeign</groupId> <artifactId>feign-okhttp</artifactId> <version>11.9.1</version> </dependency> <!-- openFeign负载均衡由ribbon改为loadbalancer--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-loadbalancer</artifactId> <version>3.1.4</version> </dependency> <!-- 解决项目启动警告:LoadBalancerCacheManager not available, returning delegate without caching.--> <!-- 如果注册中心有自己的缓存,那么就可以禁用loadbalancer的缓存--> <dependency> <groupId>com.github.ben-manes.caffeine</groupId> <artifactId>caffeine</artifactId> <version>3.1.1</version> </dependency> <!-- 解决项目启动警告:Spring Cloud LoadBalancer is currently working with the default cache. You can switch to using Caffeine cache, by adding it and org.springframework.cache.caffeine.CaffeineCacheManager to the classpath.--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> </dependency>