• 基于seata实现分布式事务实现订单服务 + 账户服务 + 商品库存服务之间的分布式事务


    概述

    实现订单服务 + 账户服务 + 商品库存服务之间的分布式事务. 订单服务生成订单,同时调用账户服务扣减金额, 调用库存服务扣减库存. 服务采用seata的刚性事务, 保证数据一致性.

    详细

    1.需求(要做什么) 

         模仿一个购物流程. 利用seata的分布式事务实现 订单服务, 账户服务, 库存服务的数据一致性.  订单服务创建订单同时: 调用账户服务扣钱, 调用库存服务扣减库存.

    2.理论概述

    Seata框架是一个业务层的XA(两阶段提交)解决方案。

    下面是一个分布式事务在Seata中的执行流程:

    1. TM 向 TC 申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的 XID。

    2. XID 在微服务调用链路的上下文中传播。

    3. RM 向 TC 注册分支事务,接着执行这个分支事务并提交(重点:RM在第一阶段就已经执行了本地事务的提交/回滚),最后将执行结果汇报给TC。

    4. TM 根据 TC 中所有的分支事务的执行情况,发起全局提交或回滚决议。

    5. TC 调度 XID 下管辖的全部分支事务完成提交或回滚请求。

    第一阶段:

    Seata的每一个RM维护了一张UNDO_LOG表, 其中保存了每一次本地事务的回滚数据, 所以能够在第一阶段直接提交事务。

    第二阶段:

    二阶段的回滚并不依赖于本地数据库事务的回滚,而是RM直接读取这张UNDO_LOG表,并将数据更新为UNDO_LOG中存储的历史数据。

    3. 代码分析

     1. 引入pom

    1. <dependency>
    2. <groupId>com.alibaba.cloud</groupId>
    3. <artifactId>spring-cloud-alibaba-seata</artifactId>
    4. <version>2.2.0.RELEASE</version>
    5. <exclusions>
    6. <exclusion>
    7. <groupId>io.seata</groupId>
    8. <artifactId>seata-spring-boot-starter</artifactId>
    9. </exclusion>
    10. </exclusions>
    11. </dependency>
    12. <dependency>
    13. <groupId>io.seata</groupId>
    14. <artifactId>seata-spring-boot-starter</artifactId>
    15. <version>1.3.0</version>
    16. </dependency>
    17. <dependency>
    18. <groupId>io.seata</groupId>
    19. <artifactId>seata-all</artifactId>
    20. <version>1.3.0</version>
    21. </dependency>

    2. 配置seata服务

    1. seata:
    2. application-id: ${spring.application.name}
    3. #需要和nacos中配置保持一致
    4. tx-service-group: kevin_tx_group
    5. config:
    6. type: nacos
    7. nacos:
    8. #需要和server在同一个注册中心下
    9. serverAddr: localhost:8848
    10. namespace: seata-server-namespace
    11. #需要server端(registry和config)、nacos配置client端(registry和config)保持一致
    12. group: SEATA_GROUP
    13. registry:
    14. type: nacos
    15. nacos:
    16. #需要和seata-server端保持一致,即server在nacos中的名称,默认为seata-server
    17. application: seata-server
    18. serverAddr: localhost:8848
    19. namespace: seata-server-namespace
    20. #需要server端(registry和config)、nacos配置client端(registry和config)保持一致
    21. group: SEATA_GROUP

    3.  @GlobalTransactional 全局事务注解

    1. @Service
    2. public class OrderService {
    3. @Autowired
    4. RestTemplate restTemplate;
    5. @Autowired
    6. JdbcTemplate jdbcTemplate;
    7. @GlobalTransactional(rollbackFor = Exception.class)
    8. @Transactional(rollbackFor = Exception.class)
    9. public void save() {
    10. String id = System.currentTimeMillis()+"";
    11. String order_no = System.currentTimeMillis()+"";
    12. Integer money = 10;
    13. Integer num = 3;
    14. jdbcTemplate.update(" INSERT INTO t_order(id, order_no, num, money) VALUES ( ?, ?, ?, ?) ", id, order_no, num, money);
    15. restTemplate.getForObject("http://localhost:8020/charge?money="+money, String.class);
    16. restTemplate.getForObject("http://localhost:8030/deduct?num="+num, String.class);
    17. }
    18. }

    4.项目文件结构截图 

    1598344959348057459.png

    5.安装部署

    5.1  创建mysql数据库  

    分别创建数据  seata-order, seata-storage, seata-account.  

    分别执行各自脚本:  脚本在 ./seata-demo-parent/sql 目录下.

    5.2  启动seata服务

    在 ./seata-demo-parent/doc/ 目录下, 解压seata-1.3.0-nacos.zip,  

    进入seata-1.3.0-nacos/bin目录, 双击 seata-server.bat

    前提 需要保证nacos启动, 且seata配置已经导入到nacos .

    5.3  导入maven项目, 并启动

    idea导入maven项目, 待maven依赖jar包下载完毕后,  分别启动

    OrderApplication, AccountApplication, StorageApplication

    image.png

    6.演示效果

    image.png

    当库存不足, 订单生成失败, 扣款失败

    image.png

  • 相关阅读:
    JavaScript 中的数组类型
    应用层 ------ HTTP协议
    学生HTML个人网页作业作品 HTML+CSS+JavaScript环保页面设计与实现制作
    消灭空指针,Java 8 给我们更好的解决方案
    PostgreSQL serial类型
    客户中心模拟(Queue and A, ACM/ICPC World Finals 2000, UVa822)rust解法
    Vue2.0打包指定路由前缀
    SSM+网上书城系统 毕业设计-附源码180919
    STL-stack
    【ROS】RViz2源码分析(二):main函数及编译配置详解
  • 原文地址:https://blog.csdn.net/hanjiepo/article/details/132797007