实用指南:SpringCloud Alibaba-Seata处理分布式事务

分布式事务

  • 一次业务操作需要跨多个数据源或需要跨多个系统进行远程调用,就会产生分布式事务问题
  • 例如:三个模块被拆分成三个独立的应用,分别使用三个独立的数据源,业务操作需要调用三个服务来完成。此时每个服务内部的数据一致性由本地事务来保证,但是全局的数据一致性问题没法保证

Seata介绍

  •  Simple Extensible Autonomous Transaction Architecture,简单可扩展自治事务框架
  • 开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务
  • 官网地址:Seata
  • GitHub:https://github.com/seata/seata

工作流程说明

核心逻辑即全局事务ID的传递和变更

XID

全局事务的唯一ID,可以在服务的调用链路中传递,绑定到服务的事务上下文中

TC->TM->RM

  • Transaction Coordinator (TC):事务协调器,维护全局事务的运行状态,负责协调并驱动全局事务的提交或回滚
  • Transaction Manager (TM):事务管理器,标注注解@GlobleTransactional启动入口的微服务模块,是全局事务的发起者,负责定义全局事务的范围,并根据TC维护的全局事务和分支事务状态,最终发起全局提交或全局回滚的决议
  • Resource Manager (RM):资源管理器,即代表数据库,负责管理分支事务上的资源,向TC注册分支事务、汇报分支事务状态,并接收TC事务协调器的指令,驱动分支(本地)事务的提交和回滚
  • 三个组件相互协作,TC以Seata 服务器(Server)形式独立部署,TM和RM则是以Seata Client的形式集成在微服务中运行

    处理流程

    • TM 向 TC 申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的 XID
    • XID 在微服务调用链路的上下文中传播
    • RM 向 TC 注册分支事务,将其纳入 XID 对应全局事务的管辖
    • TM 向 TC 发起针对 XID 的全局提交或回滚决议
    • TC 调度 XID 下管辖的全部分支事务完成提交或回滚请求

    下载安装

    • 建立seata的数据库,相关建表语句在安装包中

    • 执行bin目录下的seata-server.bat启动seata
    • 访问seata,账号密码均是seata,http://localhost:7091

    • 访问nacos

    案例实现

    • POM依赖引入
    
    
    	com.alibaba.cloud
    	spring-cloud-starter-alibaba-seata
    
    • YML配置

    # ========================seata===================
    seata:
      registry:
        type: nacos
        nacos:
          server-addr: 127.0.0.1:8848
          namespace: ""
          group: SEATA_GROUP
          application: seata-server
      tx-service-group: default_tx_group # 事务组,由它获得TC服务的集群名称
      service:
        vgroup-mapping: # 点击源码分析
          default_tx_group: default # 事务组与TC服务集群的映射关系
      data-source-proxy-mode: AT
    • 在service逻辑方法上标注注解@GlobalTransactional
    //Exception异常时进行回滚,name需要唯一
    @GlobalTransactional(name = "fsp-create-order",rollbackFor = Exception.class)
    public void create(Order order) {
    	log.info("------->下单开始");
    	orderDao.create(order);
    	//远程调用库存服务扣减库存
    	log.info("------->order-service中扣减库存开始");
    	storageService.decrease(order.getProductId(), order.getCount());
    	log.info("------->order-service中扣减库存结束");
    	//远程调用账户服务扣减余额
    	log.info("------->order-service中扣减余额开始");
    	accountService.decrease(order.getUserId(),order.getMoney());
    	log.info("------->order-service中扣减余额结束");
    	//修改订单状态为已完成
    	log.info("------->order-service中修改订单状态开始");
    	orderDao.update(order.getUserId(),0);
    	log.info("------->order-service中修改订单状态结束");
    	log.info("------->下单结束");
    }

      AT模式

      整体机制

      • 一阶段:业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源
      • 二阶段:提交异步化,非常快速地完成。回滚通过一阶段的回滚日志进行反向补偿

      一阶段加载

      • 在一阶段,Seata 会拦截“业务 SQL”
      • 解析 SQL 语义,找到“业务 SQL”要更新的业务数据,在业务数据被更新前,将其保存成“before image
      • 执行“业务 SQL”更新业务数据,在业务数据更新之后,将其保存成“after image”,最后生成行锁
      • 以上操作全部在一个数据库事务内完成,这样保证了一阶段操作的原子性

      二阶段提交 

      • 二阶段,如果业务逻辑顺利执行完成,将SQL数据提交
      • 因为“业务 SQL”在一阶段已经提交至数据库,所以Seata框架只需将一阶段保存的快照数据和行锁删掉,完成数据清理即可

      二阶段回滚

      • 二阶段如果是回滚的话,Seata 就需要回滚一阶段已经执行的“业务 SQL”,还原业务数据
      • 回滚方式便是用“before image”还原业务数据;但在还原前要首先要校验脏写,对比“数据库当前业务数据”和 “after image
      • 如果两份数据完全一致就说明没有脏写,可以还原业务数据,如果不一致就说明有脏写,出现脏写就需要转人工处理

      posted @ 2025-12-15 12:20  clnchanpin  阅读(51)  评论(0)    收藏  举报