分布式seata案例学习-2

news/2024/4/20 18:33:31/文章来源:https://blog.csdn.net/hjklnmyuiop/article/details/127245140

上篇文章学习了如何安装seata,先学习如何使用
事务的4个特性ACID
事务特性
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
at模式详解
AT模式运行机制
AT模式的特点就是对业务无入侵式,整体机制分二阶段提交
两阶段提交协议的演变:

  • 一阶段:业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。
  • 二阶段:
    • 提交异步化,非常快速地完成。
    • 回滚通过一阶段的回滚日志进行反向补偿。
      在 AT 模式下,用户只需关注自己的业务SQL,用户的业务SQL 作为一阶段,Seata 框架会自动生成事务的二阶段提交和回滚操作。
      在这里插入图片描述

Seata具体实现步骤

  1. TM端使用@GlobalTransaction进行全局事务开启、提交、回滚
  2. TM开始RPC调用远程服务
  3. RM端seata-client通过扩展DataSourceProxy,实现自动生成UNDO_LOG与TC上报
  4. TM告知TC提交/回滚全局事务
  5. TC通知RM各自执行commit/rollback操作,同时清除undo_log

RM实现

  1. 创建订单和库存服务的DB
-- 库存服务DB执行
CREATE TABLE `tab_storage` (`id` bigint(11) NOT NULL AUTO_INCREMENT,`product_id` bigint(11) DEFAULT NULL COMMENT '产品id',`total` int(11) DEFAULT NULL COMMENT '总库存',`used` int(11) DEFAULT NULL COMMENT '已用库存',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
INSERT INTO `tab_storage` (`product_id`, `total`,`used`)VALUES ('1', '96', '4');
INSERT INTO `tab_storage` (`product_id`, `total`,`used`)VALUES ('2', '100','0');-- 订单服务DB执行
CREATE TABLE `tab_order` (`id` bigint(11) NOT NULL AUTO_INCREMENT,`user_id` bigint(11) DEFAULT NULL COMMENT '用户id',`product_id` bigint(11) DEFAULT NULL COMMENT '产品id',`count` int(11) DEFAULT NULL COMMENT '数量',`money` decimal(11,0) DEFAULT NULL COMMENT '金额',`status` int(1) DEFAULT NULL COMMENT '订单状态:0:创建中;1:已完成',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
  1. 各数据库加入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,`ext` varchar(100) DEFAULT NULL,PRIMARY KEY (`id`),UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
  1. 编写业务代码

库存代码

package com.seata.storage;import com.seata.storage.model.Storage;
import com.seata.storage.service.StorageService;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@SpringBootApplication
@MapperScan("com.seata.storage.mapper")
@EnableDiscoveryClient
@EnableFeignClients
public class StorageApplication {@Autowiredprivate StorageService storageService;@GetMapping("storage/change")public Boolean change(long used , long productId){Storage storage = new Storage();storage.setTotal(100).setProductId(productId).setUsed(3);return storageService.create(storage);}public static void main(String[] args) {SpringApplication.run(StorageApplication.class, args);}
}

订单代码

package com.seata.order;import com.seata.order.model.Order;
import com.seata.order.service.OrderService;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;import java.math.BigDecimal;@RestController
@SpringBootApplication
@MapperScan("com.seata.order.mapper")
@EnableDiscoveryClient
@EnableFeignClients
public class OrderApplication {@Autowiredprivate OrderService orderService;@GetMapping("order/create")public Boolean create(long userId , long productId){Order order = new Order();order.setCount(1).setMoney(BigDecimal.valueOf(88)).setProductId(productId).setUserId(userId).setStatus(0);return orderService.create(order);}public static void main(String[] args) {SpringApplication.run(OrderApplication.class, args);}}
  1. 测试业务代码是否正常运行(完整代码见附件链接:https://pan.baidu.com/s/1vnaulywP-GLk5rGvtJulPg?pwd=e7vk
    提取码:e7vk)
  2. 在这里插入图片描述
  3. TM实现
    搭建business服务,pom、bootstrap.yml与RM基本一致,并提供FeignClient调用组件
    FeignClient组件代码编写
@FeignClient(value = "storage-service")
@Component
public interface StorageClient {@GetMapping("api/storage/change")Boolean changeStorage(@RequestParam("productId") long productId , @RequestParam("used")  int used);
}@FeignClient(value = "order-service")
@Component
public interface OrderClient {@GetMapping("api/order/create")Boolean create(@RequestParam("userId") long userId , @RequestParam("productId") long productId);
}

调用层代码编写

package com.seata.business;import com.seata.business.feign.OrderClient;
import com.seata.business.feign.StorageClient;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@SpringBootApplication
@RestController
@EnableFeignClients
@EnableDiscoveryClient
public class BusinessApplication {@Autowiredprivate OrderClient orderClient;@Autowiredprivate StorageClient storageClient;@GetMapping("buy")@GlobalTransactionalpublic String buy(long userId , long productId){orderClient.create(userId , productId);storageClient.changeStorage(userId , 1);return "ok";}public static void main(String[] args) {SpringApplication.run(BusinessApplication.class, args);}}

TM测试请求
在这里插入图片描述
如果在order与storage服务器出现以下语句表示分布式事务成功
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【复习整理归纳】| C++面经网络相关(三)

文章目录计算机网络性能指标计算机在发送文件前需要做许多前期的工作分层结构概念OSI参考模型数据链路层ARP网络协议UDP套接字TCPTCP粘包三次握手四次握手为什么建立连接协议是三次握手,而关闭连接却是四次挥手呢?为什么TIME_WAIT状态还需要等2MSL后才能…

C++ | 12天学好C++ (Day 12)->结构图可视化、代码加通俗理解

为每天进步一点点而努力。 C是计算机视觉的重要的一部分,虽然在初始学习时Python应用比较广,但是大多数公司还是C做计算机视觉类的比较多,因为C可加密,所以我们来一起探索吧!看了这系列博客,将会学到C的基…

#边学边记 必修4 高项:对事的管理 第4章 项目进度管理之 制定进度计划

制订进度计划的输入、工具与技术和输出 制定进度计划过程分析活动顺序、持续时间、资源需求和进度制约因素,创建项目进度模型的过程。主要作用是把活动、持续时间、资源、资源可用性和逻辑关系代入进度规划工具,从而形成包含各个项目活动的计划日期的进…

在docker安装的centos容器内设置远程链接

写在前面 写在前面 运维这个行业,不需要按照顺序学习。 比如你学会了基础命令,直接学docker和k8s,和学会了基础命令开始学服务难度差不多。 再比如你学会了基础命令直接学shell脚本,也能学的会。 所以我一直主张,…

WEB漏洞-文件操作之文件下载读取全解

目录 前言: (一)前置知识 (二)文件下载读取漏洞利用 1、网站目录的获取: 0x01 字典 0x02 网络爬虫 0x03 fuzz 0x04 自动化工具 0x05 下载传参的脚步文件 0x06 配合其他漏洞 2、下载数据库,操作系统配置文件 0x01 Window…

非空约束

1.创建表时添加约束   创建完表后,添加非空约束 删除name的非空约束

Vue3.0----组件基础【上】(第二章)

一、单页面应用程序 1. 什么是单页面应用程序 单页面应用程序(英文名:Single Page Application)简称 SPA,顾 名思义,指的是一个 Web 网站中只有唯一的一个 HTML 页面,所有的 功能与交互都在这唯一的一个页…

(六)Shell编程之函数、脚本引用、符号展开、重定向

一、定义函数 shell中函数的定义格式如下: [ function ] funname [()] {action;[return int;] }说明: 可以带function fun()定义,也可以直接fun()定义,如果带function函数名后的小括号可以省略。返回值语句[return int;]可以不写…

软件项目管理:外包 outsourcing、采购 procurement、合同 contracts

文章目录外包不同类型为什么选择外包好处坏处采购 procurementplanning 阶段-弄清需求 & 市场 / 评估风险Source 阶段-确定供应商具体过程RFxState of Work (SOW)评估步骤 Evaluation processManage 阶段Contract 合同定义种类固定价格合同适用场景(保守&#x…

稀疏矩阵的压缩存储

目录 稀疏矩阵的定义 稀疏矩阵的转置 代码实现 运行结果 稀疏矩阵的定义 假设在 m * n 的矩阵中&#xff0c;有 t 个元素不为零&#xff0c;且 t<<m*n&#xff0c;则称此矩阵为稀疏矩阵。按照常规的存储方法&#xff0c;稀疏矩阵很浪费内存空间&#xff0c;所以采取…

学习梦想家CMS内容管理系统-环境启动

gitee官网中项目的地址&#xff1a;首先准备里面提到的工具其中JDK8和MySQL5.7我们已经有了&#xff0c;现在需要准备另外的工具。 Spring Tool Suite 4&#xff08;STS&#xff09; 安装过程在《1-1-Spring Tool Suite 4&#xff08;STS&#xff09;的下载安装》 Redis 安装…

数字孪生在电网系统开发建设,如何选择可视化平台?

随着新能源发展规模持续增大&#xff0c;电网作为能源转换利用和输送配置的枢纽平台&#xff0c;其功能、结构和形态发生了深刻变化。同时&#xff0c;随着现代计算机技术发展&#xff0c;数字孪生成为电网向数字化转型、提高电网调度运行决策的准确性与实时性提供关键技术支撑…

初识数据库-MySQL数据库

文章目录数据库数据库的相关概念常见的关系型数据库管理系统MySQL数据库MySQL目录结构MySQL数据模型数据库 数据库的相关概念 数据库 存储数据的仓库&#xff0c;数据是有组织的进行存储英文&#xff1a; DataBase,简称 DB 数据库管理系统 管理数据库的大型软件英文&#xff…

震撼上新丨云和恩墨新一代数据库存储 zStorage 和数据库一体机 zData X 即将发布...

存储&#xff0c;在一定程度上可以称为数据库存储&#xff0c;存储与数据库的发展总是相生相随。技术上&#xff0c;数据库对高 I/O 频率、低时延、高可靠性的追求一直是存储更快、更高、更强需求的来源。商业上&#xff0c;两家影响世界的公司 Oracle 和 EMC 几乎同时起步于 1…

使用element ui的el-upload组件上传图片,记录一下

使用element ui的el-upload组件上传图片 效果预览 下面是实现效果,接口方面是把有两个接口,一个接口上传图片,传参是图片和路径,返回值是路径。另一个接口是上传表单内容(用户,地址,照片),照片是传一个路径。具体实现 html <el-form-item label="上传照片"…

第二十一章 函数递归

一、函数递归调用介绍 函数不仅可以嵌套定义,还可以嵌套调用,即在调用一个函数的过程中,函数内部又调用另一个函数,而函数的递归调用指的是在调用一个函数的过程中又直接或间接地调用该函数本身。例如在调用f1的过程中,又调用f1,这就是直接调用函数f1本身def f1():print(…

springboot(三)

视频链接&#xff1a;https://www.bilibili.com/video/BV1XQ4y1m7ex/?vd_source9545770e4a2968c05878ffac8589ec6c 视频选集&#xff1a;P58— P92 文章目录1.接口架构风格-RESTful1.1 认识REST1.2 RESTful的注解1.2.1 PathVariable1.2.2 PostMapping1.2.3 DeleteMapping1.2.4…

分布式缓存

本文介绍关于缓存的常用设计模式。以及如何保证缓存的一致性进行分类讨论。 还会介绍关于缓存失效的常见问题&#xff0c;以及针对缓存失效的解决方法。 在高并发的环境下&#xff0c;比如春节抢票大战&#xff0c;一到放票的时间节点&#xff0c;分分钟大量用户以及黄牛的各种…

魔改xxl-job,彻底告别手动配置任务!

xxl-job是一款非常优秀的任务调度中间件,轻量级、使用简单,但是苦于手动注册任务久矣,今天就来魔改一下,实现任务的自动注册!原创:微信公众号 码农参上,欢迎分享,转载请保留出处。哈喽大家好啊,我是Hydra。 xxl-job是一款非常优秀的任务调度中间件,轻量级、使用简单、…

12个小细节让普源示波器使用更加高效(上)

俗话说细节决定成败&#xff0c;示波器作为电子测量的第一工具&#xff0c;虽然使用简单&#xff0c;但并不是每个人都能注意到细节。运用好细节&#xff0c;可以使你的示波器使用更加的便捷。以下由安泰测试带来普源示波器测量相关的12个小细节可作为示波器常识快速自检的小文…