一 案例操作

1.1 背景说明

本案例的操作是在第1篇关于seta博客的基础上,后续进行操作的。

案例逻辑:这里有3个服务:一个订单服务,一个库存服务,一个账户服务

1.当用户下单时,会在订单服务中创建一个订单,

2.然后通过远程调用库存服务来扣减下单商品的库存,

3.再通过远程调用账户服务来扣减用户账户里面的余额,

4.最后在订单服务中修改订单状态为已完成。

1.2 逻辑流程图

1.3 操作案例

1.3.1 创建库,表

1.seata_order   存储订单数据库

CREATE DATABASE seata_order;
USE seata_order;
CREATE TABLE t_order(id BIGINT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY ,user_id BIGINT(11) DEFAULT NULL COMMENT '用户id',product_id BIGINT(11) DEFAULT NULL COMMENT '产品id',count INT(11) DEFAULT NULL COMMENT '数量',money DECIMAL(11,0) DEFAULT NULL COMMENT '金额',status INT(1) DEFAULT NULL COMMENT '订单状态:0创建中,1已完结'
)ENGINE=InnoDB AUTO_INCREMENT=7 CHARSET=utf8;

2.seata_storage   存储库存的数据库

CREATE DATABASE seata_storage;
USE seata_storage;
CREATE TABLE t_storage(id BIGINT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY ,product_id BIGINT(11) DEFAULT NULL COMMENT '产品id',total INT(11) DEFAULT NULL COMMENT '总库存',used INT(11) DEFAULT NULL COMMENT '已用库存',residue INT(11) DEFAULT NULL COMMENT '剩余库存'
)ENGINE=InnoDB AUTO_INCREMENT=7 CHARSET=utf8;
INSERT INTO t_storage(id, product_id, total, used, residue) VALUES(1,1,100,0,100);

3.seata_account:存储账户信息的数据库

CREATE DATABASE seata_account;
USE seata_account;
CREATE TABLE t_account(id BIGINT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY ,user_id BIGINT(11) DEFAULT NULL COMMENT '用户id',total DECIMAL(10,0) DEFAULT NULL COMMENT '总额度',used DECIMAL(10,0) DEFAULT NULL COMMENT '已用额度',residue DECIMAL(10,0) DEFAULT 0 COMMENT '剩余可用额度'
)ENGINE=InnoDB AUTO_INCREMENT=7 CHARSET=utf8;
INSERT INTO t_account(id, user_id, total, used, residue) VALUES(1,1,1000,0,1000);

4.undo.log表

在3个库中分别建立对应的回滚日志表undo_log:为各个微服务模块的数据库添加事务回滚表 undo_log ,切记用到的微服务都要创建这张表。

-- the table to store seata xid data
-- 0.7.0+ add context
-- you must to init this sql for you business databese. the seata server not need it.
-- 此脚本必须初始化在你当前的业务数据库中,用于AT 模式XID记录。与server端无关(注:业务数据库)
-- 注意此处0.3.0+ 增加唯一索引 ux_undo_logdrop table if exists `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,`ext` varchar(100) DEFAULT NULL,PRIMARY KEY (`id`),UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

5.最后,查看所建立的表

1.3.2 新建工程seta-order

1.pom文件

<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>1.3.2</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!--feign--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><!-- 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.4.2</version></dependency><!--SpringCloud ailibaba nacos --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><!-- SpringBoot整合Web组件 --><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.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.4</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId></dependency><dependency><groupId>com.fasterxml.jackson.datatype</groupId><artifactId>jackson-datatype-joda</artifactId><version>2.9.6</version></dependency><dependency><groupId>com.fasterxml.jackson.module</groupId><artifactId>jackson-module-parameter-names</artifactId></dependency><!-- 分页插件 --><dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-starter</artifactId><version>1.2.5</version></dependency><!-- alibaba的druid数据库连接池 --><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.1.9</version></dependency><!-- lombok --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency>

2.application配置文件

# nacos配置
server:port: 6001spring:datasource:name: mysql_testtype: com.alibaba.druid.pool.DruidDataSource#druid相关配置druid:#监控统计拦截的filtersfilters: statdriver-class-name: com.mysql.jdbc.Driver#基本属性url: jdbc:mysql://127.0.0.1:3306/seata_order?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=trueusername: rootpassword: cloudiip#配置初始化大小/最小/最大initial-size: 1min-idle: 1max-active: 20#获取连接等待超时时间max-wait: 60000#间隔多久进行一次检测,检测需要关闭的空闲连接time-between-eviction-runs-millis: 60000#一个连接在池中最小生存的时间min-evictable-idle-time-millis: 300000validation-query: SELECT 'x'test-while-idle: truetest-on-borrow: falsetest-on-return: false#打开PSCache,并指定每个连接上PSCache的大小。oracle设为true,mysql设为false。分库分表较多推荐设置为falsepool-prepared-statements: falsemax-pool-prepared-statement-per-connection-size: 20application:name: seata-order-servercloud:nacos:discovery:server-addr: localhost:8848 #Nacos服务注册中心地址#config:# server-addr: localhost:8848 #Nacos作为配置中心地址#file-extension: yaml #指定yaml格式的配置#group: DEV_GROUP_ljf#namespace: 05573840-fcf3-472d-a64a-c66b4fe878f4alibaba:seata: #设置事务分支 默认就是 my_test_tx_grouptx-service-group: default_tx_group
mybatis:mapper-locations: classpath:mapper/*.xmltype-aliases-package: com.ljf.mscloud.modelconfiguration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#pagehelper
pagehelper:helperDialect: mysqlreasonable: truesupportMethodsArguments: trueparams: count=countSqlreturnPageInfo: check
seata:enabled: trueenable-auto-data-source-proxy: truetx-service-group: default_tx_group #此处与上面config.txt中的vgroupMapping一致registry:type: nacosnacos:application: seata-server    #服务name要和nacos中保持一致 默认就是seata-serverserver-addr: 127.0.0.1:8848  #根据自己情况调整username: nacos              #根据自己情况调整password: nacos          #根据自己情况调整cluster: defaultgroup: DEV_GROUP_ljfnamespace: 05573840-fcf3-472d-a64a-c66b4fe878f4  #根据自己情况调整config:type: nacosnacos:server-addr: 127.0.0.1:8848 #根据自己情况调整group: DEV_GROUP_ljfusername: nacos       #根据自己情况调整password: nacos         #根据自己情况调整dataId: seata-server.propertiesnamespace: 05573840-fcf3-472d-a64a-c66b4fe878f4    #根据自己情况调整service:vgroup-mapping:default_tx_group: default
feign:hystrix:enabled: false

3.controller

@RestController
public class OrderController {@Resourceprivate OrderService orderService;@GetMapping("/order/create")public CommonResult create(Order order){orderService.create(order);return new CommonResult(200,"订单创建成功");}}

4.service

1.接口

public interface OrderService {void create(Order order);
}

2.实现类

package com.ljf.mscloud.service.impl;import com.ljf.mscloud.dao.OrderDao;
import com.ljf.mscloud.model.Order;
import com.ljf.mscloud.service.AccountService;
import com.ljf.mscloud.service.OrderService;
import com.ljf.mscloud.service.StorageService;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import javax.annotation.Resource;
import java.util.List;/*** @ClassName: OrderServiceImpl* @Description: TODO* @Author: admin* @Date: 2023/03/01 19:05:06 * @Version: V1.0**/
@Service
@Slf4j
public class OrderServiceImpl  implements OrderService {@Resourceprivate OrderDao orderDao;@Resourceprivate StorageService storageService;@Resourceprivate AccountService accountService;/*** 创建订单->调用库存服务扣减库存->调用账户服务扣减账户余额->修改订单状态* 简单说:下订单->扣库存->减余额->改状态*/@Override//  @GlobalTransactional(name = "fsp-create-order",rollbackFor = Exception.class)public void create(Order order){log.info("----->开始新建订单");//1 新建订单orderDao.create(order);//2 扣减库存log.info("----->订单微服务开始调用库存,做扣减Count");storageService.decreaseStorage(order.getProductId(),order.getCount());log.info("----->订单微服务开始调用库存,做扣减end");//3 扣减账户log.info("----->订单微服务开始调用账户,做扣减Money");accountService.decreaseAccount(order.getUserId(),order.getMoney());log.info("----->订单微服务开始调用账户,做扣减end");//4 修改订单状态,从零到1,1代表已经完成log.info("----->修改订单状态开始");orderDao.update(order.getUserId(),0);log.info("----->修改订单状态结束");log.info("----->下订单结束了,O(∩_∩)O哈哈~");}
}

3.StorageFeginclient:

@FeignClient(value = "seata-storage-server")
public interface StorageService
{@PostMapping(value = "/storage/decrease")CommonResult decreaseStorage(@RequestParam("productId") Long productId, @RequestParam("count") Integer count);
}

4.AccountFeginClient

@FeignClient(value = "seata-account-server")
public interface AccountService
{@PostMapping(value = "/account/decrease")CommonResult decreaseAccount(@RequestParam("userId") Long userId, @RequestParam("money") BigDecimal money);
}

5.model

1.order

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Order
{private Long id;private Long userId;private Long productId;private Integer count;private BigDecimal money;private Integer status; //订单状态:0:创建中;1:已完结
}

2.commonresult

@Data
@AllArgsConstructor
@NoArgsConstructor
public class CommonResult<T>
{private Integer code;private String  message;private T       data;public CommonResult(Integer code, String message){this(code,message,null);}
}

6.mapper

1.dao

@Mapper
public interface OrderDao {//1 新建订单void create(Order order);//2 修改订单状态,从零改为1void update(@Param("userId") Long userId, @Param("status") Integer status);
}

2.mapper

<?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="com.ljf.mscloud.dao.OrderDao" ><resultMap id="BaseResultMap" type="com.ljf.mscloud.model.Order"><id column="id" property="id" jdbcType="BIGINT"/><result column="user_id" property="userId" jdbcType="BIGINT"/><result column="product_id" property="productId" jdbcType="BIGINT"/><result column="count" property="count" jdbcType="INTEGER"/><result column="money" property="money" jdbcType="DECIMAL"/><result column="status" property="status" jdbcType="INTEGER"/></resultMap><insert id="create">insert into t_order (id,user_id,product_id,count,money,status)values (null,#{userId},#{productId},#{count},#{money},0);</insert><update id="update">update t_order set status = 1where user_id=#{userId} and status = #{status};</update>
</mapper>

7.启动类

@EnableDiscoveryClient
@SpringBootApplication
@EnableAutoDataSourceProxy
@EnableFeignClients
public class App
{public static void main( String[] args ){SpringApplication.run(App.class, args);System.out.println("服务启动成功!!!!!!!");}
}

1.3.3 工程seta-storage

1.pom文件

<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>1.3.2</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!--feign--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><!-- 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.4.2</version></dependency><!--SpringCloud ailibaba nacos --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><!-- SpringBoot整合Web组件 --><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.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.4</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId></dependency><dependency><groupId>com.fasterxml.jackson.datatype</groupId><artifactId>jackson-datatype-joda</artifactId><version>2.9.6</version></dependency><dependency><groupId>com.fasterxml.jackson.module</groupId><artifactId>jackson-module-parameter-names</artifactId></dependency><!-- 分页插件 --><dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-starter</artifactId><version>1.2.5</version></dependency><!-- alibaba的druid数据库连接池 --><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.1.9</version></dependency><!-- lombok --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency>

2.application配置文件

# nacos配置
server:port: 6002spring:datasource:name: mysql_testtype: com.alibaba.druid.pool.DruidDataSource#druid相关配置druid:#监控统计拦截的filtersfilters: statdriver-class-name: com.mysql.jdbc.Driver#基本属性url: jdbc:mysql://127.0.0.1:3306/seata_storage?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=trueusername: rootpassword: cloudiip#配置初始化大小/最小/最大initial-size: 1min-idle: 1max-active: 20#获取连接等待超时时间max-wait: 60000#间隔多久进行一次检测,检测需要关闭的空闲连接time-between-eviction-runs-millis: 60000#一个连接在池中最小生存的时间min-evictable-idle-time-millis: 300000validation-query: SELECT 'x'test-while-idle: truetest-on-borrow: falsetest-on-return: false#打开PSCache,并指定每个连接上PSCache的大小。oracle设为true,mysql设为false。分库分表较多推荐设置为falsepool-prepared-statements: falsemax-pool-prepared-statement-per-connection-size: 20application:name: seata-storage-servercloud:nacos:discovery:server-addr: localhost:8848 #Nacos服务注册中心地址#config:# server-addr: localhost:8848 #Nacos作为配置中心地址#file-extension: yaml #指定yaml格式的配置#group: DEV_GROUP_ljf#namespace: 05573840-fcf3-472d-a64a-c66b4fe878f4alibaba:seata: #设置事务分支 默认就是 my_test_tx_grouptx-service-group: default_tx_group
mybatis:mapper-locations: classpath:mapper/*.xmltype-aliases-package: com.ljf.mscloud.modelconfiguration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#pagehelper
pagehelper:helperDialect: mysqlreasonable: truesupportMethodsArguments: trueparams: count=countSqlreturnPageInfo: check
seata:enabled: trueenable-auto-data-source-proxy: truetx-service-group: default_tx_group #此处与上面config.txt中的vgroupMapping一致registry:type: nacosnacos:application: seata-server    #服务name要和nacos中保持一致 默认就是seata-serverserver-addr: 127.0.0.1:8848  #根据自己情况调整username: nacos              #根据自己情况调整password: nacos          #根据自己情况调整cluster: defaultgroup: DEV_GROUP_ljfnamespace: 05573840-fcf3-472d-a64a-c66b4fe878f4  #根据自己情况调整config:type: nacosnacos:server-addr: 127.0.0.1:8848 #根据自己情况调整group: DEV_GROUP_ljfusername: nacos       #根据自己情况调整password: nacos         #根据自己情况调整dataId: seata-server.propertiesnamespace: 05573840-fcf3-472d-a64a-c66b4fe878f4    #根据自己情况调整service:vgroup-mapping:default_tx_group: default
feign:hystrix:enabled: false

3.controller

@RestController
public class StorageController {@Autowiredprivate StorageService storageService;/*** 扣减库存*/@RequestMapping("/storage/decrease")public CommonResult decrease(Long productId, Integer count) {storageService.decrease(productId, count);return new CommonResult(200,"扣减库存成功!");}
}

4.service

public interface StorageService {/*** 扣减库存*/void decrease(Long productId, Integer count);
}

5.dao

@Service
public class StorageServiceImpl implements StorageService {private static final Logger LOGGER = LoggerFactory.getLogger(StorageServiceImpl.class);@Resourceprivate StorageDao storageDao;/*** 扣减库存*/@Overridepublic void decrease(Long productId, Integer count) {LOGGER.info("------->storage-service中扣减库存开始");storageDao.decrease(productId,count);LOGGER.info("------->storage-service中扣减库存结束");}
}
<mapper namespace="com.ljf.mscloud.dao.StorageDao"><resultMap id="BaseResultMap" type="com.ljf.mscloud.model.Storage"><id column="id" property="id" jdbcType="BIGINT"/><result column="product_id" property="productId" jdbcType="BIGINT"/><result column="total" property="total" jdbcType="INTEGER"/><result column="used" property="used" jdbcType="INTEGER"/><result column="residue" property="residue" jdbcType="INTEGER"/></resultMap><update id="decrease">UPDATEt_storageSETused = used + #{count},residue = residue - #{count}WHEREproduct_id = #{productId}</update></mapper>

6.model

1.Storage

@Data
public class Storage {private Long id;/*** 产品id*/private Long productId;/*** 总库存*/private Integer total;/*** 已用库存*/private Integer used;/*** 剩余库存*/private Integer residue;
}

2.commonResult

@Data
@AllArgsConstructor
@NoArgsConstructor
public class CommonResult<T>
{private Integer code;private String  message;private T       data;public CommonResult(Integer code, String message){this(code,message,null);}
}

7.启动类

@EnableDiscoveryClient
@SpringBootApplication
@EnableAutoDataSourceProxy
@EnableFeignClients
public class App
{public static void main( String[] args ){SpringApplication.run(App.class, args);System.out.println("服务启动成功!!!!!!!");}
}

1.3.4 工程seta-account

1.pom文件

 <dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>1.3.2</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!--feign--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><!-- 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.4.2</version></dependency><!--SpringCloud ailibaba nacos --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><!-- SpringBoot整合Web组件 --><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.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.4</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId></dependency><dependency><groupId>com.fasterxml.jackson.datatype</groupId><artifactId>jackson-datatype-joda</artifactId><version>2.9.6</version></dependency><dependency><groupId>com.fasterxml.jackson.module</groupId><artifactId>jackson-module-parameter-names</artifactId></dependency><!-- 分页插件 --><dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-starter</artifactId><version>1.2.5</version></dependency><!-- alibaba的druid数据库连接池 --><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.1.9</version></dependency><!-- lombok --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency>

2.application配置文件

# nacos配置
server:port: 6003spring:datasource:name: mysql_testtype: com.alibaba.druid.pool.DruidDataSource#druid相关配置druid:#监控统计拦截的filtersfilters: statdriver-class-name: com.mysql.jdbc.Driver#基本属性url: jdbc:mysql://127.0.0.1:3306/seata_account?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=trueusername: rootpassword: cloudiip#配置初始化大小/最小/最大initial-size: 1min-idle: 1max-active: 20#获取连接等待超时时间max-wait: 60000#间隔多久进行一次检测,检测需要关闭的空闲连接time-between-eviction-runs-millis: 60000#一个连接在池中最小生存的时间min-evictable-idle-time-millis: 300000validation-query: SELECT 'x'test-while-idle: truetest-on-borrow: falsetest-on-return: false#打开PSCache,并指定每个连接上PSCache的大小。oracle设为true,mysql设为false。分库分表较多推荐设置为falsepool-prepared-statements: falsemax-pool-prepared-statement-per-connection-size: 20application:name: seata-account-servercloud:nacos:discovery:server-addr: localhost:8848 #Nacos服务注册中心地址#config:# server-addr: localhost:8848 #Nacos作为配置中心地址#file-extension: yaml #指定yaml格式的配置#group: DEV_GROUP_ljf#namespace: 05573840-fcf3-472d-a64a-c66b4fe878f4alibaba:seata: #设置事务分支 默认就是 my_test_tx_grouptx-service-group: default_tx_group
mybatis:mapper-locations: classpath:mapper/*.xmltype-aliases-package: com.ljf.mscloud.modelconfiguration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#pagehelper
pagehelper:helperDialect: mysqlreasonable: truesupportMethodsArguments: trueparams: count=countSqlreturnPageInfo: check
seata:enabled: trueenable-auto-data-source-proxy: truetx-service-group: default_tx_group #此处与上面config.txt中的vgroupMapping一致registry:type: nacosnacos:application: seata-server    #服务name要和nacos中保持一致 默认就是seata-serverserver-addr: 127.0.0.1:8848  #根据自己情况调整username: nacos              #根据自己情况调整password: nacos          #根据自己情况调整cluster: defaultgroup: DEV_GROUP_ljfnamespace: 05573840-fcf3-472d-a64a-c66b4fe878f4  #根据自己情况调整config:type: nacosnacos:server-addr: 127.0.0.1:8848 #根据自己情况调整group: DEV_GROUP_ljfusername: nacos       #根据自己情况调整password: nacos         #根据自己情况调整dataId: seata-server.propertiesnamespace: 05573840-fcf3-472d-a64a-c66b4fe878f4    #根据自己情况调整service:vgroup-mapping:default_tx_group: default
feign:hystrix:enabled: false

3.controller

@RestController
public class AccountController {@ResourceAccountService accountService;/*** 扣减账户余额*/@RequestMapping("/account/decrease")public CommonResult decrease(@RequestParam("userId") Long userId, @RequestParam("money") BigDecimal money){accountService.decrease(userId,money);return new CommonResult(200,"扣减账户余额成功!");}
}

4.service

public interface AccountService {/*** 扣减账户余额* @param userId 用户id* @param money 金额*/void decrease(@RequestParam("userId") Long userId, @RequestParam("money") BigDecimal money);
}
/*** 账户业务实现类* Created by zzyy on 2019/11/11.*/
@Service
public class AccountServiceImpl implements AccountService {private static final Logger LOGGER = LoggerFactory.getLogger(AccountServiceImpl.class);@ResourceAccountDao accountDao;/*** 扣减账户余额*/@Overridepublic void decrease(Long userId, BigDecimal money) {LOGGER.info("------->account-service中扣减账户余额开始");//模拟超时异常,全局事务回滚//暂停几秒钟线程//  try { TimeUnit.SECONDS.sleep(20); } catch (InterruptedException e) { e.printStackTrace(); }accountDao.decrease(userId,money);LOGGER.info("------->account-service中扣减账户余额结束");}
}

5..dao

@Mapper
public interface AccountDao {/*** 扣减账户余额*/void decrease(@Param("userId") Long userId, @Param("money") BigDecimal money);
}

6.model

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Account {private Long id;/*** 用户id*/private Long userId;/*** 总额度*/private BigDecimal total;/*** 已用额度*/private BigDecimal used;/*** 剩余额度*/private BigDecimal residue;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CommonResult<T>
{private Integer code;private String  message;private T       data;public CommonResult(Integer code, String message){this(code,message,null);}
}

7.启动类

@EnableDiscoveryClient
@SpringBootApplication
@EnableAutoDataSourceProxy
@EnableFeignClients
public class App
{public static void main( String[] args ){SpringApplication.run(App.class, args);System.out.println("服务启动成功!!!!!!!");}
}

1.4  测试环节

1.4.1 服务启动准备阶段

需求先启动nacos,seata这个两个服务,然后启动工程seata-order,seata-storage,seata-account这3个工程。

1.4.2正常访问阶段

1.查看3张表

2请求访问后

http://localhost:6001/order/create?userId=001&productId=001&count=1&money=400&status=0

访问后,再次观察3张表,均按照:下订单->扣库存->减余额->改状态 流程执行正确无误。

1.4.3 超时异常,没有加@GlobalTransaction

1.在账户模块中,模拟超时,延迟20s,再次启动账户模块

2.再次访问,页面报错

3.查看这3张表,发现库存表实现了减库存,账户实现了减余额操作,新订单表中也新增了1条订单数据,但是订单状态还是0,订单状态没有完成改变。

 4. 原因在于:调用账户模块超时,导致订单模块发生异常,无法进行最后一步修改订单状态逻辑的执行。

1.4.4 超时异常,添加@GlobalTransaction

1.在订单模块中,执行方法新增 @GlobalTransaction注解,重启order服务

2.多次刷新后,虽然前端还是报错,只是显示问题不管

http://localhost:6001/order/create?userId=001&productId=001&count=1&money=400&status=0

3.可以查看订单表,库存表,账户表均没有发生改变,说明添加@GlobalTransaction

已经启动作用,分布式事务已经起作用。

springcloud3 Seata实现订单、库存、账户3者之间的分布式事务3相关推荐

  1. 分布式事务原理及实战seata(转自微信公众号 终码一生 )

    什么是分布式事务? _____________________________________________________________________________ 分布式对应的是单体架构, ...

  2. 使用Seata彻底解决Spring Cloud中的分布式事务问题!

    摘要 Seata是Alibaba开源的一款分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务,本文将通过一个简单的下单业务场景来对其用法进行详细介绍. 什么是分布式事务问题? 单体应用 单 ...

  3. seata xid是什么_使用Seata彻底解决Spring Cloud中的分布式事务问题!

    Seata是Alibaba开源的一款分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务,本文将通过一个简单的下单业务场景来对其用法进行详细介绍. 什么是分布式事务问题? 单体应用 单体应用 ...

  4. 分布式事务 seata 最全入门教程

    基本介绍 什么是分布式事务 指一次大的操作由不同的小操作组成的,这些小的操作分布在不同的服务器上,分布式事务需要保证这些小操作要么全部成功,要么全部失败.从本质上来说,分布式事务就是为了保证不同数据库 ...

  5. 微服务-分布式事务seata

    什么是分布式事务 单体应用被拆分成微服务应用,原来的三个模块被拆分成三个独立的应用,分别使用三个独立的数据源, 业务操作需要调用三个服务来完成.此时每个服务内部的数据一致性由本地事务来保证,但是全局的 ...

  6. 阿里开源的分布式事务揭秘:Seata原理及流程剖析

    背景 在分布式系统中,分布式事务是一个必须要解决的问题,目前使用较多的是最终一致性方案.今天带来的这篇,就给大家分析一下Seata的源码是如何一步一步实现的.读源码的时候我们需要俯瞰起全貌,不要去扣一 ...

  7. 分布式事务之Seata中间件原理及流程详细分析

    转载自:https://blog.csdn.net/f4761/article/details/89077400 背景 在分布式系统中,分布式事务是一个必须要解决的问题,目前使用较多的是最终一致性方案 ...

  8. Spring Cloud入门-Seata处理分布式事务问题(Hoxton版本)

    我们先从官网下载seata-server,这里下载的是seata-server-1.0.0.zip,下载地址:https://github.com/seata/seata/releases 这里我们使 ...

  9. 分布式事务——分布式事务简介、分布式事务框架 Seata(AT模式、Tcc模式、Tcc Vs AT)、分布式事务—MQ

    分布式事务--分布式事务简介.分布式事务框架 Seata(AT模式.Tcc模式.Tcc Vs AT).分布式事务--MQ 一.分布式事务简介 如果不是分布式环境的话一般不会接触到这种,一旦是微服务这种 ...

最新文章

  1. 澳洲专升硕计算机专业,澳洲计算机专升硕-纽卡斯尔大学
  2. python与人工智能编程-Python是人工智能和机器学习的最佳编程语言,证据在此!...
  3. oracle 三个口令管理,Oracle学习笔记(12)口令和资源管理
  4. JPDA 架构研究5 - Agent利用环境指针访问VM (内存管理篇)
  5. python如何问问题_Python简单问答程序如何解决问题循环
  6. 内置函数——hasattr() 函数
  7. 《跟我一起做J2EE版Blog–jPress》6(Spring集成Struts2,打通第一个Action)
  8. 常用的JS格式化函数,手机号和身份证号脱敏处理等
  9. 网络中的常见的各种协议--报文格式总结学习
  10. 社交网络分析(igraph)
  11. 汽车智能化新赛道——CMS国标明年1月1日落地,供应链已提前布局
  12. 【EXLIBRIS】#小词旮旯# 005 Pupil
  13. 神仙打架!清华公布2020特奖候选人名单,有人三篇顶会一作,还有人...
  14. 【欢聚时代】HR独家传授YY笔试面经小秘诀!
  15. android 如何去控制第三方音乐播放app之控制QQ音乐
  16. C语言编写一个函数,实现计算并返回一个整数的平方(或立方)
  17. 腾讯主机安全“猎刃计划”发布,WebShell挑战赛再燃起,PHPer燥起来
  18. git学习笔记[idea整合GitHub,Gitee](非常详细)
  19. 高斯移动热源,熔池流场分布,comsol模拟案例
  20. C++ vector find()使用? ( if!=vec.end())

热门文章

  1. matlab 数学建模 绘制颜色渐变的彩虹图
  2. Structured Comparative Analysis of Systems Logs to Diagnose Performance Problems
  3. 紫光云三个月上线,背后是一个怎样的布局?
  4. java程序设计基础篇_Java语言程序设计(基础篇) 第一章
  5. Java 命令行参数
  6. multiparty 中间件源码解析
  7. MySQL数据库表从一个数据库复制到另一个数据库
  8. 服务器分发系统如何做性能测试,如何针对音视频流媒体服务器分发的RTSP视频流进行并发压力测试?...
  9. 计算机也能成为艺术家?(基于论文A Neural Algorithm of Artistic Style的图像风格迁移)
  10. 不能安装pil_安装PIL遇到的问题