Spring Cloud Alibaba Seata 搭建以及分布式事务的验证

Spring Cloud Alibaba Seata 搭建以及分布式事务的验证

1.seata 简介

  • Seata(Simple Extensible Autonomous Transaction Architecture)是一种开源的分布式事务解决方案,旨在解决微服务架构下的分布式事务问题。它提供了一套完整的分布式事务管理功能,包括全局事务管理、本地事务协调和分布式事务恢复等。
  • 在传统的单体应用中,使用关系型数据库的事务机制可以确保数据的一致性和隔离性。然而,在微服务架构中,每个微服务都有自己独立的数据库,无法直接使用传统事务进行跨服务的一致性控制。这就导致了分布式事务的挑战。
  • Seata 提供了分布式事务的解决方案,通过引入一个事务协调器(Transaction Coordinator)来协调多个参与者(Participants)之间的本地事务。Seata 支持两阶段提交(Two-Phase Commit)和补偿事务(Compensating Transaction)两种模式。
  • 在 Seata 的架构中,事务发起者(Transaction Coordinator)负责全局事务的创建、提交和回滚,并协调各个参与者的事务操作。参与者(Participants)执行具体的本地事务操作,并与事务协调器进行通信。事务管理器(Transaction Manager)负责协调全局和本地事务的提交和回滚,以及事务的状态管理。
  • Seata 提供了与各种主流数据库和框架的集成支持,例如 MySQL、Oracle、Spring Boot 等,使得在现有的微服务架构中引入分布式事务变得更加方便。

2. seata的三大角色

  • 事务协调者(Transaction Coordinator,TC)- 维护全局和分支事务的状态,驱动全局事务提交或回滚,是整个分布式事务的核心。
  • 事务管理器(Transaction Manager,TM)- 定义全局事务的范围,开始全局事务、提交或回滚全局事务。
  • 资源管理器(Resource Manager,RM)- 管理分支事务处理的资源,与 TC 交流以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。
  • 其中,TC 是单独部署的 Server 服务端,TM 和 RM 则是嵌入到应用中的 Client 客户端。由于 TC 是独立的服务端,它与 TM 和 RM 进行通信的接口被称为 RPC(Remote Procedure Call,远程过程调用)接口。具体来讲,TM 和 RM 向 TC 发送关于事务的请求,TC 则根据请求的类型进行相应的响应和操作,从而实现分布式事务的一致性和可靠性。

在这里插入图片描述

3. Seata的流程

  • TM发起一个全局事务请求,请求TC开启一个全局事务。TC为该全局事务生成一个全局唯一的事务ID(XID)gloab_table就是存储的全局事务信息。
  • RM将本地事务注册为该全局事务的分支事务,并通过XID进行关联。RM会与TC进行通信,报告分支事务的状态,分支事务存储在brance_table。
  • TM根据业务逻辑执行相关操作,操作涉及的资源由RM管理。
  • 当TM完成所有操作后,请求TC提交或回滚该全局事务。TC收到请求后,驱动所有参与者(RM)执行相应的提交或回滚操作。每个参与者根据TC的指令将其本地事务提交或回滚

4. Seata AT模式

  • 第一阶段
    业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。核心在于对业务sql进行解析,转换成undolog.
    AT模式官方网址

  • 第二阶段
    1.分布式事务操作成功,则TC通知RM异步删除undolog
    2.分布式事务操作失败,TM向TC发送回滚请求,RM 收到协调器TC发来的回滚请求,通过 XID 和 Branch ID 找到相应的回滚日志记录,通过回滚记录生成反向的更新 SQL 并执行,以完成分支的回滚。

  • 优势
    应用层基于SQL解析实现了自动补偿,从而最大程度的降低业务侵入性;
    将分布式事务中TC(事务协调者)独立部署,负责事务的注册、回滚;
    通过全局锁实现了写隔离与读隔离。

5. Seata搭建

下载seata1.3版本
修改file.conf
在这里插入图片描述

修改register.conf
在这里插入图片描述

找到模板案例,照着抄

案例需要vpn
在这里插入图片描述

复制数据库创建语句自己创建出来,作为保存相关必要的数据
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
csdn不让上传文件,我将所有需要的文件打包放入网盘
这里的两个文件也在里面
在这里插入图片描述
运行刚才放入的文件
注意nacos这里默认是开启的

  sh nacos-config.sh -h 192.168.14.3  -p 8848 -g SEATA_GROUP

可在windows客户端中查看相应刚刚配置的文件
搭建的nacos的ip加上端口号,必须加上/nacos 账号密码均为nacos
在这里插入图片描述
需要修改
在刚刚打开的网页中找到并修改记得一定要修改时区

  • url

      jdbc:mysql://192.168.14.53:3306/seata——global?useUnicode=true&serverTimezone=UTC
    

username,和password改为自己的
在这里插入图片描述
启动服务
在这里插入图片描述
使用这个命令记得改java的环境变量为java8.

 bin/seata-server.sh   -p 8091  -n 1 
 bin/seata-server.sh   -p 8092  -n 2

在这里插入图片描述

6. Seata Client快速开始

6.1 声明式事务实现(@GlobalTransactional)

接入微服务应用
业务场景:
用户下单,整个业务逻辑由两个微服务构成:

  • 订单服务:根据采购需求创建订单。
  • 库存服务:对给定的商品扣除库存数量。

6.2 添加依赖

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>

6.3 各微服务对应配置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,
  PRIMARY KEY (`id`),
  UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

6.4 测试

  1. 订单

调用方法后 通过openfeign调用 stock-app的stock接口 记得检查是否注入

@RestController
public class OrderController {
    @Autowired
    OrderItemDao orderItemDao;

    @Autowired
    OrderDao orderDao;
    @Autowired
    StockClient stockClient;

    @PostMapping("/add")
    @GlobalTransactional(name = "addOrder")
    public String add(@RequestBody Ordering ordering){
        String yy = DateUtil.format(DateUtil.date(), "YYYYMMDDHHmmssSSS");
        Long aLong = Long.valueOf(yy);
        ordering.setId(aLong);
        orderDao.addOrderMaster(ordering);
        List<OrderingProduct> products = ordering.getProducts();
        for(OrderingProduct product : products){
            product.setOrderId(aLong);
            orderItemDao.addOrderItem(product);
            stockClient.upQty(product.getProductId(),product.getQty());
        }
        return "yes";
    }
}

这是调用的方法

@GetMapping("/stock")
    @GlobalTransactional(name = "addOrder")
    public String upQty(Integer productId,Integer qty){
        int a = 5/0;
        inventoryDao.updateQty(qty,productId);
        inventoryLogDao.log("产品ID为" + productId + "减少数量" + qty);

        return null;
    }

6.6 只需要一个公共注解代替原始注解

@GlobalTransactional(name = “addOrder”)
俩个一定要有相同的名字,可以共同成功,共同失败

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值