在seata基础教程上-seata 1.4.2的安装及基于Nacos的配置[1]中,我们基于Nacos完成了Seata的安装及配置,这篇文章我们介绍下在Spring Cloud Alibaba中的使用。
环境准备
学习本文之前,你应该准备好以下环境。
•Nacos 2.0.2版本并运行•Seata Server 1.4.2版本,配置好Nacos并运行
前置知识
本文通过Spring Cloud Alibaba,使用Nacos作为服务中心,通过OpenFeign实现服务之间的调用,所以你必须具备以下基础知识:
1.在Spring Cloud中使用Nacos作为服务注册、发现中心的配置及使用。2.在Spring Cloud中通过OpenFeign实现服务之间的调用。3.MyBatis的使用。
场景描述
本文参考尚硅谷阳哥的视频教程,使用最新的Nacos(2.0.2)及Seata(1.4.2),演示用户下单的业务场景,基本流程如下

其实业务很简单,用户下单,扣减商品库存表数据然后减去账户余额,如果不是微服务架构,我们一般使用一个系统,基本上一个@Transactional
注解就解决了。基于微服务就不同了,我们提供三个微服务,分别为订单服务、库存服务、账户服务,三个服务对应三个数据库,分别为seata_order、seata_storage、seata_account,现在不同业务分布在不同的数据库中,那么我们在进行数据回滚就不太好处理了。
Seata的分布式交易解决方案

有了Seata就简单了,我们只需要使用一个@GlobalTransactional
注解在业务方法上就可以了。
Spring Cloud使用Seata
创建数据库
创建三个数据库,分别为seata_order
、seata_storage
、seata_account
。
订单微服务表结构
create table t_order(id bigint auto_increment comment '主键',user_id bigint null comment '用户Id',product_id bigint null,count int null,money decimal(11) null,status int(1) null,constraint t_order_id_uindex unique (id));alter table t_order add primary key (id);
create table undo_log ( id bigint auto_increment primary key, branch_id bigint not null, xid varchar(100) not null, context varchar(128) not null, rollback_info longblob not null, log_status int not null, log_created datetime not null, log_modified datetime not null, constraint ux_undo_log unique (xid, branch_id) ) charset=utf8;
### 账户微服务表结构```javacreate table t_account(id bigint auto_increment,user_id bigint null,total decimal null,used decimal null,residue decimal null,constraint t_account_id_uindexunique (id));alter table t_accountadd primary key (id);create table undo_log(id bigint auto_incrementprimary key,branch_id bigint not null,xid varchar(100) not null,context varchar(128) not null,rollback_info longblob not null,log_status int not null,log_created datetime not null,log_modified datetime not null,constraint ux_undo_logunique (xid, branch_id))charset=utf8;INSERT INTO seata_account.t_account (id, user_id, total, used, residue) VALUES (1, 1, 1000, 0, 1000);
库存微服务表结构
create table t_storage(id bigint auto_increment,product_id bigint null,total int null,used int null,residue int null comment '剩余库存',constraint t_storage_id_uindexunique (id));alter table t_storageadd primary key (id);create table undo_log(id bigint auto_incrementprimary key,branch_id bigint not null,xid varchar(100) not null,context varchar(128) not null,rollback_info longblob not null,log_status int not null,log_created datetime not null,log_modified datetime not null,constraint ux_undo_logunique (xid, branch_id))charset=utf8;INSERT INTO seata_storage.t_storage (id, product_id, total, used, residue) VALUES (2, 1, 100, 0, 100);

创建工程
工程结构,如下图,请忽略其他模块。

[alt type="warning"] 一定要注意依赖里面的版本号,不然会出现各种错误。[/alt]
创建父工程
父工程用于维护依赖管理,没有具体代码。
增加依赖
<?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>net.xiangcaowuyu</groupId><artifactId>Cloud2020</artifactId><version>1.0-SNAPSHOT</version><packaging>pom</packaging><modules><module>cloud-provider-payment8001</module><module>cloud-consumer-order80</module><module>cloud-api-common</module><module>cloud-provider-payment8004</module><module>cloud-consumerzk-order80</module><module>cloud-consumer-feign-order80</module><module>cloud-provider-hystrix-payment8001</module><module>cloud-consumer-feign-hystrix-order80</module><module>cloud-consumer-hystrix-dashboard9001</module><module>cloud-gateway-gateway9527</module><module>cloud-config-center-3344</module><module>cloud-config-client-3355</module><module>cloud-config-client-3366</module><module>cloud-stream-rabbitmq-provider8801</module><module>cloud-stream-rabbitmq-consumer8802</module><module>cloud-stream-rabbitmq-consumer8803</module><module>cloud-stream-rabbitmq-consumer8802</module><module>cloud-stream-rabbitmq-consumer8803</module><module>cloud-stream-rabbitmq-consumer8803</module><module>cloudalibaba-provider-payment9001</module><module>cloudalibaba-provider-payment9002</module><module>cloudalibaba-consumer-order80</module><module>cloudalibaba-config-nacos-client3377</module><module>cloudalibaba-sentinel-service8401</module><module>seata-order-service2001</module><module>seata-storage-service2002</module><module>seata-account-service2003</module></modules><!-- 统一管理jar包版本--><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target><junit.version>4.12</junit.version><log4j.version>1.2.17</log4j.version><lombok.version>1.16.18</lombok.version><mysql.version>5.1.47</mysql.version><druid.version>1.1.16</druid.version><mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version></properties><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>2.3.12.RELEASE</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>Hoxton.SR12</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><!-- <version>2.1.0.RELEASE</version>--><version>2.2.1.RELEASE</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>${druid.version}</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>${mysql.version}</version></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>${mybatis.spring.boot.version}</version></dependency></dependencies></dependencyManagement><build><pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) --><plugins><plugin><artifactId>maven-clean-plugin</artifactId><version>3.1.0</version></plugin><plugin><artifactId>maven-site-plugin</artifactId><version>3.7.1</version></plugin><plugin><artifactId>maven-project-info-reports-plugin</artifactId><version>3.0.0</version></plugin></plugins></pluginManagement><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-site-plugin</artifactId><configuration><locales>en,fr</locales></configuration></plugin></plugins></build><reporting><plugins><plugin><artifactId>maven-project-info-reports-plugin</artifactId></plugin></plugins></reporting></project>
创建通用模块
通用模块这里维护了一个CommonResult
用于返回Json
对象。
增加依赖
<?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>Cloud2020</artifactId><groupId>net.xiangcaowuyu</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>cloud-api-common</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId></dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.7.5</version></dependency></dependencies></project>
增加实体
package net.xiangcaowuyu.springcloud.entites;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;/*** 博客:https://www.xiangcaowuyu.net* Description:** @Author: 香草物语* DateTime: 2021-07-24 11:25*/@Data@AllArgsConstructor@NoArgsConstructorpublic class CommonResult<T> {private Integer code;private String message;private T data;public CommonResult(Integer code, String message) {this(code, message, null);}}
创建订单微服务模块
订单模块维护订单微服务,通过Feign调用库存及账户微服务。
增加依赖
<?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>Cloud2020</artifactId><groupId>net.xiangcaowuyu</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>seata-order-service2001</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId></dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.7.5</version></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><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.4.2</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId></dependency><dependency><groupId>net.xiangcaowuyu</groupId><artifactId>cloud-api-common</artifactId><version>1.0-SNAPSHOT</version></dependency></dependencies></project>
修改配置文件
配置文件一定要注意,tx-service-group
一定要与我们Seata服务端的配置保持一致。
server:port: 2001spring:application:name: seata-order-servicecloud:nacos:discovery:server-addr: localhost:1111loadbalancer:retry:enabled: falsedatasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://127.0.0.1:3306/seata_order?useSSL=falseusername: rootpassword: rootfeign:hystrix:enabled: falsemybatis:type-aliases-package: net.xiangcaowuyu.springcloud.alibaba.seata.domainmapperLocations: classpath:/mapper/*.xmlseata:tx-service-group: my_tx_group #与config.txt 中的service.vgroupMapping.my_tx_group=default一致service:vgroup-mapping:my_tx_group: default #与config.txt 中的service.vgroupMapping.my_tx_group=default一致config:type: nacosnacos:server-addr: localhost:1111group: "SEATA_GROUP"namespace: ""username: "nacos"password: "nacos"
增加实体
@Data@AllArgsConstructor@NoArgsConstructorpublic class Order {/*** 主键*/private Long id;/*** 用户Id*/private Long userId;private Long productId;private Integer count;private BigDecimal money;private Integer status;}
增加Mapper
public interface OrderDao {int create(Order record);int update(@Param("userId") Long userId, @Param("status") Integer status);
数据库操作
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="net.xiangcaowuyu.springcloud.alibaba.seata.dao.OrderDao"><resultMap id="BaseResultMap" type="net.xiangcaowuyu.springcloud.alibaba.seata.domain.Order"><!--@Table t_order--><result column="id" jdbcType="BIGINT" property="id"/><result column="user_id" jdbcType="BIGINT" property="userId"/><result column="product_id" jdbcType="BIGINT" property="productId"/><result column="count" jdbcType="INTEGER" property="count"/><result column="money" jdbcType="DECIMAL" property="money"/><result column="status" jdbcType="INTEGER" property="status"/></resultMap><sql id="Base_Column_List"><!--@mbg.generated-->id, user_id, product_id, `count`, money, `status`</sql><insert id="create" parameterType="net.xiangcaowuyu.springcloud.alibaba.seata.domain.Order"><!--@mbg.generated-->insert into t_order (user_id, product_id,`count`, money, `status`)values (#{userId,jdbcType=BIGINT}, #{productId,jdbcType=BIGINT},#{count,jdbcType=INTEGER}, #{money,jdbcType=DECIMAL}, #{status,jdbcType=INTEGER})</insert><update id="update">update t_orderset status = 1where user_id = #{userId}and status = #{status}</update></mapper>
增加服务接口
增加账户微服务Feign调用接口
@FeignClient(value = "seata-account-service")public interface IAccountService {@PostMapping("/account/decrease")public CommonResult accountDecrease(@RequestParam("userId") Long userId, @RequestParam("money") BigDecimal money);}
增加库存微服务Feign调用接口
@FeignClient(value = "seata-storage-service")public interface IStorageService {@PostMapping("/storage/decrease")public CommonResult storageDecrease(@RequestParam("productId") Long productId,@RequestParam("count") Integer count);}
增加订单接口
public interface IOrderService {int create(Order record);}
增加订单服务实现
@Service@Slf4jpublic class OrderServiceImpl implements IOrderService {@Resourceprivate OrderDao orderDao;@Resourceprivate IStorageService storageService;@Resourceprivate IAccountService accountService;@Override@GlobalTransactional(name = "fsp-create-order")// @Transactionalpublic int create(Order order) {log.info("--------->开始新建订单");orderDao.create(order);log.info("--------->订单微服务开始调用库存,做扣减Count");storageService.storageDecrease(order.getProductId(), order.getCount());log.info("--------->订单微服务开始调用库存,做扣减End");log.info("--------->订单微服务开始调用账户,做扣减Money");accountService.accountDecrease(order.getUserId(), order.getMoney());log.info("--------->订单微服务开始调用账户,做扣减End");log.info("--------->修改订单状态开始");orderDao.update(order.getUserId(), 0);log.info("--------->修改订单状态End");return 1;}}
增加接口controller
@RestController@Slf4j@RequestMapping("/order")public class OrderController {@Resourceprivate IOrderService orderService;@PostMapping("/create")public CommonResult create(Order order) {orderService.create(order);return new CommonResult(200, "订单创建成功");}}
增加DataSource,让Seata代理数据库
@Configurationpublic class DataSourceProxyConfig {@Bean@ConfigurationProperties(prefix = "spring.datasource")public DataSource druidDataSource(){return new DruidDataSource();}}
修改启动类
取消数据源自动配置,让Seata能够代理数据源。
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)@EnableDiscoveryClient@EnableFeignClients@MapperScan(basePackages = {"net.xiangcaowuyu.springcloud.alibaba.seata.dao"})public class SeataOrderServiceMain2001 {public static void main(String[] args) {SpringApplication.run(SeataOrderServiceMain2001.class, args);}}
创建库存微服务模块
库存微服务用于提供扣减库存的微服务接口。
增加依赖
<?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>Cloud2020</artifactId><groupId>net.xiangcaowuyu</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>seata-storage-service2002</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId></dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.7.5</version></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId></dependency><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.4.2</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId></dependency><dependency><groupId>net.xiangcaowuyu</groupId><artifactId>cloud-api-common</artifactId><version>1.0-SNAPSHOT</version></dependency></dependencies></project>
修改配置文件
server:port: 2002spring:application:name: seata-storage-servicecloud:nacos:discovery:server-addr: localhost:1111loadbalancer:retry:enabled: falsedatasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://127.0.0.1:3306/seata_storage?useSSL=falseusername: rootpassword: rootfeign:hystrix:enabled: falsemybatis:type-aliases-package: net.xiangcaowuyu.springcloud.alibaba.seata.domainmapperLocations: classpath:/mapper/*.xmlseata:tx-service-group: my_tx_group #与config.txt 中的service.vgroupMapping.my_tx_group=default一致service:vgroup-mapping:my_tx_group: default #与config.txt 中的service.vgroupMapping.my_tx_group=default一致config:type: nacosnacos:server-addr: localhost:1111group: "SEATA_GROUP"namespace: ""username: "nacos"password: "nacos"
增加实体
@Data@AllArgsConstructor@NoArgsConstructorpublic class Storage {private Long id;private Long productId;private Integer total;private Integer used;private Integer residue;}
增加Mapper
public interface StorageDao {int decrease(@Param("productId") Long productId, @Param("count") Integer count);}
数据库操作
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="net.xiangcaowuyu.springcloud.alibaba.seata.dao.StorageDao"><resultMap id="BaseResultMap" type="net.xiangcaowuyu.springcloud.alibaba.seata.domain.Storage"><!--@Table t_storage--><result column="id" jdbcType="BIGINT" property="id"/><result column="product_id" jdbcType="BIGINT" property="productId"/><result column="total" jdbcType="INTEGER" property="total"/><result column="used" jdbcType="INTEGER" property="used"/><result column="residue" jdbcType="INTEGER" property="residue"/></resultMap><sql id="Base_Column_List">id,product_id,total,used,residue</sql><update id="decrease">update t_storageset used = used + #{count},residue = residue - #{count}where product_id = #{productId}</update></mapper>
增加服务接口
public interface IStorageService {int decrease(Long productId, Integer count);}
增加服务实现
@Service@Slf4jpublic class StorageServiceImpl implements IStorageService {@Resourceprivate StorageDao storageDao;@Override// @Transactionalpublic int decrease(Long productId, Integer count) {log.info("--------->storage-------decrease获取xid:" + RootContext.getXID());return storageDao.decrease(productId, count);}}
增加接口controller
@RestController@RequestMapping("/storage")@Slf4jpublic class StorageController {@Resourceprivate IStorageService storageService;@PostMapping("/decrease")public CommonResult decrease(@RequestParam("productId") Long productId, @RequestParam("count") Integer count) {storageService.decrease(productId, count);return new CommonResult(200, "扣减库存成功");}}
增加DataSource,让Seata代理数据源
@Configurationpublic class DataSourceProxyConfig {@Bean@ConfigurationProperties(prefix = "spring.datasource")public DataSource druidDataSource(){return new DruidDataSource();}}
修改启动类
取消数据源自动配置,让Seata能够代理数据源。
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)@EnableDiscoveryClient@EnableFeignClients@MapperScan(basePackages = {"net.xiangcaowuyu.springcloud.alibaba.seata.dao"})public class SeataStorageServiceMain2002 {public static void main(String[] args) {SpringApplication.run(SeataStorageServiceMain2002.class, args);}}
创建账户微服务模块
账户微服务用于提供扣减账户金额的微服务接口。
增加依赖
<?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>Cloud2020</artifactId><groupId>net.xiangcaowuyu</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>seata-account-service2003</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId></dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.7.5</version></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><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.4.2</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId></dependency><dependency><groupId>net.xiangcaowuyu</groupId><artifactId>cloud-api-common</artifactId><version>1.0-SNAPSHOT</version></dependency></dependencies></project>
修改配置文件
server:port: 2003spring:application:name: seata-account-servicecloud:nacos:discovery:server-addr: localhost:1111loadbalancer:retry:enabled: falsedatasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://127.0.0.1:3306/seata_account?useSSL=falseusername: rootpassword: rootfeign:hystrix:enabled: falsemybatis:type-aliases-package: net.xiangcaowuyu.springcloud.alibaba.seata.domainmapperLocations: classpath:/mapper/*.xmlseata:tx-service-group: my_tx_group #与config.txt 中的service.vgroupMapping.my_tx_group=default一致service:vgroup-mapping:my_tx_group: default #与config.txt 中的service.vgroupMapping.my_tx_group=default一致config:type: nacosnacos:server-addr: localhost:1111group: "SEATA_GROUP"namespace: ""username: "nacos"password: "nacos"
增加实体
@Data@AllArgsConstructor@NoArgsConstructorpublic class Account {private Long id;private Long userId;private Long total;private Long used;private Long residue;}
增加Mapper
public interface AccountDao {int decrease(@Param("userId") Long userId, @Param("money") BigDecimal money);}
数据库操作
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="net.xiangcaowuyu.springcloud.alibaba.seata.dao.AccountDao"><resultMap id="BaseResultMap" type="net.xiangcaowuyu.springcloud.alibaba.seata.domain.Account"><!--@Table t_account--><result column="id" jdbcType="BIGINT" property="id"/><result column="user_id" jdbcType="BIGINT" property="userId"/><result column="total" jdbcType="DECIMAL" property="total"/><result column="used" jdbcType="DECIMAL" property="used"/><result column="residue" jdbcType="DECIMAL" property="residue"/></resultMap><sql id="Base_Column_List">id,user_id,total,used,residue</sql><update id="decrease">update t_accountset used = used + #{money},residue=residue - #{money}where user_id = #{userId}</update></mapper>
增加服务接口
public interface IAccountService {int decrease( Long userId, BigDecimal money);}
增加服务实现
这里注意以下,我们模拟了报错信息
@Service@Slf4jpublic class AccountServiceImpl implements IAccountService {@Resourceprivate AccountDao accountDao;@Override// @Transactionalpublic int decrease(Long userId, BigDecimal money) {log.info("--------->storage-------decrease获取xid:" + RootContext.getXID());//模拟报错int age = 10 / 0;return accountDao.decrease(userId, money);}}
增加接口controller
@RestController@Slf4j@RequestMapping("/account")public class AccountController {@Resourceprivate IAccountService accountService;@PostMapping("/decrease")public CommonResult decrease(@RequestParam("userId") Long userId, @RequestParam("money") BigDecimal money) {accountService.decrease(userId, money);return new CommonResult(200, "账户扣减成功");}}
增加DataSource,让Seata代理数据源
@Configurationpublic class DataSourceProxyConfig {@Value("${mybatis.mapperLocations}")private String mapperLocations;@Bean@ConfigurationProperties(prefix = "spring.datasource")public DataSource druidDataSource(){return new DruidDataSource();}}
修改启动类
取消数据源自动配置,让Seata能够代理数据源。
@EnableDiscoveryClient@EnableFeignClients@MapperScan(basePackages = {"net.xiangcaowuyu.springcloud.alibaba.seata.dao"})@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)public class SeataAccountServiceMain2003 {public static void main(String[] args) {SpringApplication.run(SeataAccountServiceMain2003.class, args);}}
测试
通过postman测试

可以看到系统抛出了异常,然后我们查看以下数据库,可以看到数据没有发生任何变化。
References
[1]
seata基础教程上-seata 1.4.2的安装及基于Nacos的配置: https://www.xiangcaowuyu.net/java/seata-foundation-tutorial-installation-of-seata-142-and-configuration-based-on-nacos.html





