• Seata介绍


        1     seata介绍

    2019 年 1 月,阿里巴巴中间件团队发起了开源项目 Fescar(Fast & EaSy Commit And
    Rollback),其愿景是让分布式事务的使用像本地事务的使用一样,简单和高效,并逐步解决开发者们遇到的分布式事务方面的所有难题。后来更名为 Seata,意为:Simple Extensible AutonomousTransaction Architecture,是一套分布式事务解决方案
            Seata的设计目标是对业务无侵入,因此从业务无侵入的2PC方案着手,在传统2PC的基础上演进。它把一个分布式事务理解成一个包含了若干分支事务的全局事务。全局事务的职责是协调其下管辖的分支事务达成一致,要么一起成功提交,要么一起失败回滚。此外,通常分支事务本身就是一个关系数据库的本地事务。

    Seata主要由三个重要组件组成:

    • TC:Transaction Coordinator 事务协调器,管理全局的分支事务的状态,用于全局性事务的提交和回滚。
    • TM:Transaction Manager 事务管理器,用于开启、提交或者回滚全局事务。
    • RM:Resource Manager 资源管理器,用于分支事务上的资源管理,向TC注册分支事务,上报分支事务的状态,接受TC的命令来提交或者回滚分支事务。

     

     Seata的执行流程如下:
    1. A服务的TM向TC申请开启一个全局事务,TC就会创建一个全局事务并返回一个唯一的XID
    2. A服务的RM向TC注册分支事务,并及其纳入XID对应全局事务的管辖
    3. A服务执行分支事务,向数据库做操作

    4. A服务开始远程调用B服务,此时XID会在微服务的调用链上传播
    5. B服务的RM向TC注册分支事务,并将其纳入XID对应的全局事务的管辖
    6. B服务执行分支事务,向数据库做操作
    7. 全局事务调用链处理完毕,TM根据有无异常向TC发起全局事务的提交或者回滚
    8. TC协调其管辖之下的所有分支事务, 决定是否回滚

    Seata实现2PC与传统2PC的差别:
    1. 架构层次方面,传统2PC方案的 RM 实际上是在数据库层,RM本质上就是数据库自身,通过XA协议实现,而 Seata的RM是以jar包的形式作为中间件层部署在应用程序这一侧的。
    2. 两阶段提交方面,传统2PC无论第二阶段的决议是commit还是rollback,事务性资源的锁都要保
    持到Phase2完成才释放。而Seata的做法是在Phase1 就将本地事务提交,这样就可以省去Phase2
    持锁的时间,整体提高效率。

    2 Seata实现分布式事务控制

    本示例通过Seata中间件实现分布式事务,模拟电商中的下单和扣库存的过程
    我们通过订单微服务执行下单操作,然后由订单微服务调用商品微服务扣除库存

    2.1  案例基本代码

    2.1.1 修改order微服务

    controller

    1. @RestController
    2. @Slf4j
    3. public class OrderController5 {
    4.   @Autowired
    5.   private OrderServiceImpl5 orderService;
    6.   //下单
    7.   @RequestMapping("/order/prod/{pid}")
    8.   public Order order(@PathVariable("pid") Integer pid) {
    9.     log.info("接收到{}号商品的下单请求,接下来调用商品微服务查询此商品信息", pid);
    10.     return orderService.createOrder(pid);
    11.  }
    12. }

    OrderService

    1. @Service
    2. @Slf4j
    3. public class OrderServiceImpl5{
    4.   @Autowired
    5.   private OrderDao orderDao;
    6.   @Autowired
    7.   private ProductService productService;
    8.   @Autowired
    9.   private RocketMQTemplate rocketMQTemplate;
    10.   @GlobalTransactional
    11.   public Order createOrder(Integer pid) {
    12.     //1 调用商品微服务,查询商品信息
    13.     Product product = productService.findByPid(pid);
    14.     log.info("查询到{}号商品的信息,内容是:{}", pid, JSON.toJSONString(product));
    15.     //2 下单(创建订单)
    16.     Order order = new Order();
    17.     order.setUid(1);
    18.     order.setUsername("测试用户");
    19.     order.setPid(pid);
    20.     order.setPname(product.getPname());
    21.     order.setPprice(product.getPprice());
    22.     order.setNumber(1);
    23.     orderDao.save(order);
    24.     log.info("创建订单成功,订单信息为{}", JSON.toJSONString(order));
    25.     //3 扣库存
    26.     productService.reduceInventory(pid, order.getNumber());
    27.  //4 向mq中投递一个下单成功的消息
    28.     rocketMQTemplate.convertAndSend("order-topic", order);
    29.     return order;
    30.  }
    31. }

    ProductService

    1. @FeignClient(value = "service-product")
    2. public interface ProductService {
    3.   //减库存
    4.   @RequestMapping("/product/reduceInventory")
    5.   void reduceInventory(@RequestParam("pid") Integer pid, @RequestParam("num")
    6. int num);
    7. }

    2.1.2 修改Product微服务

    controller

    1. //减少库存
    2. @RequestMapping("/product/reduceInventory")
    3. public void reduceInventory(Integer pid, int num) {
    4.   productService.reduceInventory(pid, num);
    5. }

    service

    1. Override
    2. public void reduceInventory(Integer pid, int num) {
    3.   Product product = productDao.findById(pid).get();
    4.   product.setStock(product.getStock() - num);//减库存
    5.   productDao.save(product);
    6. }

     2.1.3 异常模拟

    在ProductServiceImpl的代码中模拟一个异常, 然后调用下单接口

    1. @Override
    2. public void reduceInventory(Integer pid, Integer number) {
    3.   Product product = productDao.findById(pid).get();
    4.   if (product.getStock() < number) {
    5.     throw new RuntimeException("库存不足");
    6.  }
    7.   int i = 1 / 0;
    8.   product.setStock(product.getStock() - number);
    9.   productDao.save(product);
    10. }

  • 相关阅读:
    Mongodb安装配置
    mysql面试题44:MySQL数据库cpu飙升的话,要怎么处理?
    R 语言nutrient数据集的可视化
    html如何向后台发送请求获取数据?Vue如何给后台发送请求获取数据?前后端如何传递数据?axios如何发送get请求?axios如何发送post请求?
    Tomcat中GET和POST请求时乱码解决
    Android 11 定制系统全局监听触摸事件接口
    【机器学习300问】135、决策树算法ID3的局限性在哪儿?C4.5算法做出了怎样的改进?
    [LeetCode周赛复盘] 第 322 场周赛20221204
    山东省技能兴鲁网络安全大赛 web方向
    【是C++,不是C艹】 类与对象 | 认识面向对象 | 访问限定符 | 封装 | this指针
  • 原文地址:https://blog.csdn.net/Lj_chuxuezhe/article/details/133273051