Spring Cloud Alibaba Seata(二)

news2025/1/12 3:50:15

目录

一、Seata

1、Seata-AT模式

 1.1、具体案例

1.2、通过Seata的AT模式解决分布式事务

2、Seata-XA模式

3、Seata-TCC模式

4、Seata-SAGA模式


一、Seata

1、Seata-AT模式

概念:AT模式是一种无侵入的分布式事务解决方案,在 AT 模式下,用户只需关注自己的“业务 SQL”,用户的 “业务 SQL” 作为一阶段,Seata 框架会自动生成事务的二阶段提交和回滚操作。
Seata AT 模式

两阶段提交协议的演变:
一阶段:业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。
二阶段:提交异步化,非常快速地完成。回滚通过一阶段的回滚日志进行反向补偿。
        在一阶段中,Seata会拦截“业务SQL“,首先解析SQL语义,找到要更新的业务数据,在数据被更新前,保存下来"undo",然后执行”业务SQL“更新数据,更新之后再次保存数据”redo“,最后生成行锁,这些操作都在本地数据库事务内完成,这样保证了一阶段的原子性。
二阶段
        相对一阶段,二阶段比较简单,负责整体的回滚和提交,如果之前的一阶段中有本地事务没有通过,那么就执行全局回滚,否在执行全局提交,回滚用到的就是一阶段记录的"undo Log",通过回滚记录生成反向更新SQL并执行,以完成分支的回滚。当然事务完成后会释放所有资源和删除所有日志。

 1.1、具体案例

1、创建两个服务,一个订单order8801 一个库存stock8802

创建数据库表

-- stock库存表
DROP TABLE IF EXISTS `t_stock`;
CREATE TABLE `t_stock` (
  `product_id` int(11) NOT NULL AUTO_INCREMENT,
  `money` int(11) DEFAULT 0,
  `count` int(11) DEFAULT 0,
  PRIMARY KEY (`product_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert into t_stock (product_id,count,money) values (1,100,10);

-- order订单表
DROP TABLE IF EXISTS `t_order`;
CREATE TABLE `t_order` (
  `product_id` int(11) NOT NULL AUTO_INCREMENT,
  `count` int(11) DEFAULT 0,
  PRIMARY KEY (`product_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

业务:订单服务通过OpenFegin远程调用库存服务,然后库存服务减库存,订单服务生成订单,完成基本的调用以后我们给订单服务添加异常

pom

    <dependencies>
        <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.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
    </dependencies>

yml

server:
  port: 8801

spring:
  application:
    name: seata-order
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
        namespace: "b98dfc17-7de8-44f1-b1e1-837fe681b96c"
        group: SEATA_GROUP
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/seata_test?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
    username: root
    password: root

seata:
  tx-service-group: mygroup
  service:
    vgroup-mapping:
      mygroup: default
  registry:
    type: nacos
    nacos:
      server-addr: localhost:8848
      group: "SEATA_GROUP"
      namespace: "b98dfc17-7de8-44f1-b1e1-837fe681b96c"
      username: "nacos"
      password: "nacos"
补充对应关系

stock8802如下端口和服务名不同其他同上
server:
  port: 8802

spring:
  application:
    name: seata-stock

订单order8801

启动类

@EnableDiscoveryClient
@EnableFeignClients
@MapperScan("com.lwz.springcloud.mapper")
@SpringBootApplication
public class Order8801Main {

    public static void main(String[] args) {
        SpringApplication.run(Order8801Main.class,args);
    }

}

控制层

@RestController
public class OrderController {
    @Autowired
    private OrderService orderService;

    @GetMapping("/order/create")
    public String create(){
        orderService.create();
        return "生成订单";
    }
}

service

public interface OrderService {
    void create();
}

serviceimpl

@Service
public class OrderServiceImpl implements OrderService {
    @Resource
    private OrderMapper orderMapper;

    @Resource
    private StockService stockService;

    @Override
    public void create() {
        // 减库存
        stockService.decrement();

        // 添加异常
        int i = 1/0;

        // 创建订单
        orderMapper.create();
    }
}

mapper

public interface OrderMapper {
    @Insert("insert into t_order (count) values (1)")
    void create();
}

feign

@FeignClient(value = "seata-stock")
public interface StockService {
    @GetMapping("/stock/decr")
    String decrement();
}

库存stock8802

启动类

@SpringBootApplication
@MapperScan("com.lwz.springcloud.mapper")
@EnableDiscoveryClient
public class Stock8802Main {

    public static void main(String[] args) {
        SpringApplication.run(Stock8802Main.class,args);
    }
}

控制层

@RestController
public class StockController {
    @Resource
    private StockService stockService;

    @GetMapping("/stock/decr")
    public String decrement(){
        stockService.decr();
        return "库存-1";
    }

}

service

public interface StockService {
    void decr();
}

serviceimpl

@Service
public class StockServiceImpl implements StockService {

    @Resource
    private StockMapper stockMapper;

    @Override
    public void decr() {
        stockMapper.decr();
    }
}

mapper

public interface StockMapper {
    @Update("update t_stock set count = count - 1 where product_id = 1")
    void decr();
}

Nacos和Seata都要进行启动,8801和8802起来
访问Order的接口测试:http://localhost:8801/order/create

此时我们会发现访问接口出现异常情况,但是库存减少,订单没有增加此时已经出现了分布式事务的问题

库存数量减一,但是订单表没数据

 

 

1.2、通过Seata的AT模式解决分布式事务

Seata依赖,上面已经添加过

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

在对应的微服务数据库上加上undo_log表,此表用于数据的回滚

undo_log表去官网上找,或源代码seata/script/client/at/db/mysql.sql下面找到AT需要的undo_log表

-- for AT mode you must to init this sql for you business database. the seata server not need it.
CREATE TABLE IF NOT EXISTS `undo_log`
(
    `branch_id`     BIGINT       NOT NULL COMMENT 'branch transaction id',
    `xid`           VARCHAR(128) NOT NULL COMMENT 'global transaction id',
    `context`       VARCHAR(128) NOT NULL COMMENT 'undo_log context,such as serialization',
    `rollback_info` LONGBLOB     NOT NULL COMMENT 'rollback info',
    `log_status`    INT(11)      NOT NULL COMMENT '0:normal status,1:defense status',
    `log_created`   DATETIME(6)  NOT NULL COMMENT 'create datetime',
    `log_modified`  DATETIME(6)  NOT NULL COMMENT 'modify datetime',
    UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = InnoDB AUTO_INCREMENT = 1 DEFAULT CHARSET = utf8mb4 COMMENT ='AT transaction mode undo table';
ALTER TABLE `undo_log` ADD INDEX `ix_log_created` (`log_created`);

需要在order8801(TM)的Controller上添加注解

@RestController
public class OrderController {
    @Autowired
    private OrderService orderService;

    @GetMapping("/order/create")
    @GlobalTransactional// 开启分布式事务
    public String create(){
        orderService.create();
        return "生成订单";
    }
}

把t_stock表删除,再把最上面的SQL语句重新执行一次,重启服务进行测试。

Nacos和Seata都要进行启动,8801和8802起来
访问Order的接口测试:http://localhost:8801/order/create

访问接口仍然会报异常,但是此时已经解决了分布式事务问题

 库存没有减少,订单也没有增加

那么为了验证undo_log表用于存储回滚的数据,我们在OrderServiceImpl上异常位置添加断点,同时以debug方式来启动8801订单服务。

然后访问接口:http://localhost:8801/order/create,程序会卡在断点上,此时我们来查看undo_log表和库存表,此时我们会发现,库存确实减少了,但是在undo_log表中出现了快照记录了当前修改前的数据,这个数据就是用于回滚的数据

undo_log表记录快照

库存减少

 放行以后,库存数量回复,回滚生效

2、Seata-XA模式

Seata XA

什么是XA?
XA 规范早在上世纪 90 年代初就被提出,用以解决分布式事务处理这个领域的问题。
注意:不存在某一种分布式事务机制可以完美适应所有场景,满足所有需求。
现在,无论 AT 模式、TCC 模式还是 Saga 模式,这些模式的提出,本质上都源自 XA 规范对某些场景需求的无法满足。

什么是XA协议?
XA 规范 是 X/Open 组织定义的分布式事务处理(DTP,Distributed Transaction Processing)标准
XA 规范 描述了全局的事务管理器与局部的资源管理器之间的接口。 XA规范 的目的是允许的多个资源(如数据库,应用服务器,消息队列等)在同一事务中访问,这样可以使 ACID 属性跨越应用程序而保持有效。
XA 规范 使用两阶段提交(2PC,Two-Phase Commit)来保证所有资源同时提交或回滚任何特定的事务。
XA 规范 在上世纪 90 年代初就被提出。目前,几乎所有主流的数据库都对 XA 规范 提供了支持。
DTP模型定义如下角色:
- AP:即应用程序,可以理解为使用DTP分布式事务的程序
- RM:资源管理器,可以理解为事务的参与者,一般情况下是指一个数据库的实例(MySql),通过资源管理器对该数据库进行控制,资源管理器控制着分支事务
- TM:事务管理器,负责协调和管理事务,事务管理器控制着全局事务,管理实务生命周期,并协调各个RM。全局事务是指分布式事务处理环境中,需要操作多个数据库共同完成一个工作,这个工作即是一个全局事务。
- DTP模式定义TM和RM之间通讯的接口规范叫XA,简单理解为数据库提供的2PC接口协议,基于数据库的XA协议来实现的2PC又称为XA方案。

3、Seata-TCC模式

        TCC 是分布式事务中的二阶段提交协议,它的全称为 Try-Confirm-Cancel,即资源预留(Try)、确认操作(Confirm)、取消操作(Cancel),他们的具体含义如下:
1. Try:对业务资源的检查并预留;
2. Confirm:对业务处理进行提交,即 commit 操作,只要 Try 成功,那么该步骤一定成功;
3. Cancel:对业务处理进行取消,即回滚操作,该步骤回对 Try 预留的资源进行释放。
        TCC 是一种侵入式的分布式事务解决方案,以上三个操作都需要业务系统自行实现,对业务系统有着非常大的入侵性,设计相对复杂,但优点是 TCC 完全不依赖数据库,能够实现跨数据库、跨应用资源管理,对这些不同数据访问通过侵入式的编码方式实现一个原子操作,更好地解决了在各种复杂业务场景下的分布式事务问题。

TCC和AT区别
AT 模式基于支持本地ACID事务的关系型数据库:
一阶段 prepare 行为:在本地事务中,一并提交业务数据更新和相应回滚日志记录。
二阶段 commit 行为:马上成功结束,自动异步批量清理回滚日志。
二阶段 rollback 行为:通过回滚日志,自动 生成补偿操作,完成数据回滚。
相应的,TCC 模式,不依赖于底层数据资源的事务支持:
一阶段 prepare 行为:调用 自定义的 prepare 逻辑。
二阶段 commit 行为:调用 自定义的 commit 逻辑。
二阶段 rollback 行为:调用 自定义的 rollback 逻辑。
所谓 TCC 模式,是指支持把 自定义的分支事务纳入到全局事务的管理中。

 特点:
1. 侵入性比较强,并且需要自己实现相关事务控制逻辑
2. 在整个过程基本没有锁,性能较强

TCC具体案例

4、Seata-SAGA模式

        Saga模式是SEATA提供的长事务解决方案,在Saga模式中,业务流程中每个参与者都提交本地事务,当出现某一个参与者失败则补偿前面已经成功的参与者,一阶段正向服务和二阶段补偿服务(执行处理时候出错了,给一个修复的机会)都由业务开发实现。

Seata saga模式

Saga 模式下分布式事务通常是由事件驱动的,各个参与者之间是异步执行的,Saga 模式是一种长事务解决方案。

Spring Cloud Alibaba Seata(一)

怕输的人永远没有资格赢!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/679876.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

git修改默认主分支main为master和设置git默认创建的项目默认分支都为master

文章目录 前言一、设置新建仓库默认分支为master1.点击GitHub右上角的头像2. 选中settings&#xff08;设置&#xff09;3.点击Repositories&#xff08;存储库&#xff09;4.更改main为master后点击update 二、设置已建仓库的默认分支为master1.找到你要改的项目点击settings&…

STL序列式容器的概念

文章目录 1 迭代器2 什么是序列式容器3 序列式容器容器中常见的函数成员参考 1 迭代器 迭代器和C指针非常类似&#xff0c;它可以是需要的任意类型&#xff0c;通过迭代器可以指向容器中的某个元素&#xff0c;如果需要&#xff0c;还可以对该元素进行读写操作。 迭代器类别 …

ThreeJS案例一——在场景中添加视频,使用人物动作以及用键盘控制在场景中行走的动画

准备 首先我们需要两个模型&#xff0c;一个是场景模型&#xff0c;另一个是人物模型。 人物模型我这里用的Threejs官网中的给的模型&#xff0c;名称是Xbot.glb。 当然人物模型也可以自己去这个网站下载sketchfab&#xff0c;下载后给模型添加动画mixamo 下载模型动画 先让…

C++ STL vector容器用法

文章目录 1 vector初始化方法2 vector容器迭代器3 data()函数4 emplace_back()和push_back()的区别5 insert()函数6 vector删除元素参考 1 vector初始化方法 方式1&#xff1a; std::vector<double> values;//创建空的vcetor values.reserve(20); //设置容器的内存分配…

【实战】 JWT、用户认证与异步请求(1) —— React17+React Hook+TS4 最佳实践,仿 Jira 企业级项目(四)

文章目录 一、项目起航&#xff1a;项目初始化与配置二、React 与 Hook 应用&#xff1a;实现项目列表三、TS 应用&#xff1a;JS神助攻 - 强类型四、JWT、用户认证与异步请求1.login2.middleware of json-server3.jira-dev-tool&#xff08;imooc-jira-tool&#xff09;安装问…

《流浪地球 2》的硬核黑科技

电影中&#xff0c;由刘德华饰演的量子计算机工程师图恒宇有一个惊心动魄的情节。为了同步启动全球地球发动机&#xff0c;需要重启互联网&#xff0c;避免地壳破碎和地质灾害。而重启互联网的关键则是要启动“根服务器”。电影中没有具体交代是什么根服务器&#xff0c;但是当…

Ubuntu18.04屏幕分辨率问题

本篇博客最早发布于实验室公共博客&#xff0c;但已无人维护&#xff0c;现迁移至个人博客 起因 本来昨天还好好的&#xff0c;过了一夜&#xff0c;就变了&#xff0c;像极了咳咳(自行脑补) redwallbot-2小车上固定的屏幕&#xff0c;屏幕分辨率本来应该是1920x1080的&#…

DevOps系列文章之 linux安装ftp

第一步 1、用root 进入系统 2、使用命令 rpm -qa|grep vsftpd 查看系统是否安装了ftp&#xff0c;若安装了vsftp&#xff0c;使用这个命令会在屏幕上显示vsftpd的版本 3、使用命令rpm -e vsftpd 即可卸载ftp 4、再使用rpm -qa|grep vsftpd 查看系统是否已删除ftp&#xff0…

【小技巧】vscode 在 JS 文件中补全 HTML标签

文章目录 vscode中有很多插件可以支持 HTML 标签自动补全&#xff0c;在.vue和.html文件中都没有问题&#xff0c;但是在使用react时&#xff0c;HTML标签是写在js或者是ts文件中&#xff0c;插件就不起作用了 解决方案&#xff1a; 在设置中插入这段设置代码 "emmet.i…

uniapp 微信小程序sourcemap映射

uniapp 微信小程序sourcemap映射 错误捕获 由于微信小程序中没有window对象&#xff0c;不能通过window.onerror和window.onunhandledRejection方法进行全局的监听。不过我们也可以使用以下几种方法。 使用try…catch 将可能出现的错误的代码使用try...catch包裹 try{cont…

【C++】一文读懂C++中的异常处理机制

文章目录 C 中的异常处理机制1.1 什么是异常&#xff1f;1.2 调用abort()1.3 返回错误码1.4 异常机制1.5 将对象用作异常类型1.6 异常规范和C111.7 栈解退1.7.1 return和throw的区别1.7.2 什么是栈解退 1.8 其他异常特性1.9 excepyion类1.9.1 stdexcept异常类1.9.2 bad_alloc异…

329款超有设计感的英文字体合集

一组超有设计感的英文字体合集&#xff0c;总共329个字库包含多种字体风格&#xff1a;手写字体、签名字体、复古字体、笔刷字体、漫画字体等无衬线字体。适用于签名、文具、标志、排版引言、杂志或书籍封面。素材获取&#xff1a;取括号内容&#xff0c;&#xff08;scwan&…

【 openGauss数据库】--运维指南01

【 openGauss数据库】--运维指南01 &#x1f53b; 一、 openGauss数据库运维指南&#x1f530; 1.1 启停openGauss&#x1f530; 1.2 查看openGauss数据库状态 &#x1f53b; 二、 维护检查项&#x1f530; 2.1 检查实例状态&#x1f530; 2.2 检查锁信息&#x1f530; 2.3 统计…

个人向非企业,基于目前主流图床的选购指南

1. 为什么需要搭建自己的图床 最近研究了一下国内外比较主流的图床与对象存储&#xff0c;因为个人写作更加偏向于使用Markdown&#xff0c;而国内很多平台如掘金&#xff0c;简书&#xff0c;csdn等等网站都做了相关的防盗链&#xff0c;即使是我为作者本人&#xff0c;想取用…

C语言里面那些你必须知道的常用关键字(详细讲解)

前言 哈喽&#xff0c;各位铁汁们好啊&#xff01;✨今天来给大家带来的是C语言中我们常用的关键字静态static的详细讲解和typedef 、#define定义常量和宏。   既然是详解想必大家必定是想学一些平常学不到的东西吧&#xff01;这里博主给大家详细讲解static修饰的变量在内存…

2023最全的Java架构师面试120题解析(MySQL/Redis/架构/高并发等)

最全架构师题目将包含如下技术范围&#xff1a; 1.Java基础和高级: 集合框架: List&#xff1a;ArrayList、LinkedList&#xff1b;Set&#xff1a;HashSet、TreeSet Map:TreeMap/ConcurrentHashMap&#xff1b;Queue:ConcurrentLinkedQueue等 泛型、反射、并发编程、JVM、A…

基于Smb协议实现网络文件传输(Golang)

在前面章节已经展示了一些关于SMB的基本介绍&#xff0c;以及对应SMB相关操作的Java实现&#xff0c;这一章主要是前一章的补充&#xff0c;使用Golang来对 SMB共享文件夹进行操作。如果没有阅读过上一章节的同学&#xff0c;请跳转到 基于Smb协议实现网络文件传输&#xff0c;…

Axure教程—折叠面手风琴效果

上文中介绍了用Axure制作折叠面板的基础制作&#xff0c;这次介绍折叠面板手机风琴效果 效果 预览地址&#xff1a;https://e18rf6.axshare.com 功能 点击标题展开内容&#xff0c;点击另一标题&#xff0c;其展开的内容折叠 制作 拖入四个动态面板&#xff0c;分别命名为1、…

PHP流程控制与文件包含:基础与关键要点

目录 PHP流程控制 顺序结构&#xff1a; 分支结构&#xff1a; Switch分支&#xff1a; PHP循环结构 for循环 while循环 do-while循环 while和do-while的区别&#xff1a; 循环控制 流程控制代替语法 PHP文件包含 PHP文件包含的作用 PHP文件包含的四种形式 PHP文…

【spring cloud学习】3、Eureka Server注册中心

Eureka本身是Netflix开源的一款注册中心产品&#xff0c;并且Spring Cloud提供了相应的集成封装。选择Eureka作为注册中心实例来讲解是出于以下原因&#xff1a; &#xff08;1&#xff09;Eureka在业界的应用十分广泛&#xff0c;整个框架经受住了Netflix严酷生产环境的考验。…