【Spring Cloud Alibaba】seata分布式事务官方入门案例(实战版)

文章目录

  • 1. 业务介绍
    • 1.1. 用例
    • 1.2. 架构图
    • 1.3. 3个服务的代码及业务逻辑(略)
  • 2. SEATA 的分布式交易解决方案
  • 3. 由Dubbo + SEATA提供支持的示例(实战)
    • 3.1. 步骤 1:建立数据库,如seata数据库
    • 3.2. 步骤 2:创建 UNDO_LOG 表
    • 3.3. 步骤 3:为示例业务创建表
    • 3.4. 步骤 4: 启动服务
    • 3.5. 步骤 5: 运行示例
    • 3.6. 测试
      • 3.6.1. 正常执行
      • 3.6.2. 模拟异常发生
      • 3.6.3. 原理简述

本文是介绍官方的seata入门案例,采用的是 微服务架构,参考地址:https://seata.io/zh-cn/docs/user/quickstart/。

代码详细地址:https://github.com/seata/seata-samples/tree/master/dubbo。

整个seata-samples代码库很大,本例只用到了dubbo子模块。

1. 业务介绍

1.1. 用例

本业务以购买商品的业务逻辑为例子。整个业务涉及到3个微服务一起提供服务:

  • 仓储服务:对给定的商品扣除仓储数量。
  • 订单服务:根据采购需求创建订单。
  • 帐户服务:从用户帐户中扣除余额。

1.2. 架构图

Architecture

1.3. 3个服务的代码及业务逻辑(略)

2. SEATA 的分布式交易解决方案

img

我们只需要使用一个 @GlobalTransactional 注解在业务方法上:

@GlobalTransactionalpublic void purchase(String userId, String commodityCode, int orderCount) {......}

备注:

1、每个微服务都与seata服务连接起来(可以看每个服务的xxx-service.xml)。如dubbo-storage-service.xml文件。其他服务也一样

    <bean id="storageDataSourceProxy" class="io.seata.rm.datasource.DataSourceProxy"><constructor-arg ref="storageDataSource" /></bean><bean name="storageDataSource" class="com.alibaba.druid.pool.DruidDataSource"init-method="init" destroy-method="close"><property name="url" value="${jdbc.storage.url}"/><property name="username" value="${jdbc.storage.username}"/><property name="password" value="${jdbc.storage.password}"/><property name="driverClassName" value="${jdbc.storage.driver}"/></bean>

2、每个服务都注册了一个GlobalTransactionScanner,字符串dubbo-demo-storage-service表示应用ID(applicationId),字符串my_test_tx_group表示事务服务组(txServiceGroup)

    <bean class="io.seata.spring.annotation.GlobalTransactionScanner"><constructor-arg value="dubbo-demo-storage-service"/><constructor-arg value="my_test_tx_group"/></bean>

3、字符串my_test_tx_group还在项目的file.conf文件中还用到了。

3. 由Dubbo + SEATA提供支持的示例(实战)

建议参考代码https://github.com/seata/seata-samples/tree/master/dubbo的readme.md文件。

3.1. 步骤 1:建立数据库,如seata数据库

3.2. 步骤 2:创建 UNDO_LOG 表

undo_log表是临时中间表,存储的是分布式事务过程中每张表变更前后的值。一条记录代表某张表变更前和变更后的详细数据。这张表的作用是需要读者理解的。

之所以记录变更前后的详细数据,就是为了在事务失败时能够进行回滚。

-- 注意此处0.3.0+ 增加唯一索引 ux_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;

3.3. 步骤 3:为示例业务创建表

3.4. 步骤 4: 启动服务

# 启动seata服务
docker run --name seata-file -p 8091:8091 hellowoodes/seata:0.9.0-file
# 启动zooekper
docker run --name zookeeper -p 2181:2181 -p 2888:2888 -p 3888:3888 -d zookeeper

3.5. 步骤 5: 运行示例

注意:作者下载代码测试的时候,以下应用都不能启动,后查阅资料,发现是缺少了jar包,请在启动出问题的时候在pom.xml中添加jar包。

<dependency><groupId>com.alibaba.spring</groupId><artifactId>spring-context-support</artifactId><version>1.0.11</version>
</dependency>
  • 启动 DubboAccountServiceStarter
  • 启动 DubboStorageServiceStarter
  • 启动 DubboOrderServiceStarter
  • 运行 DubboBusinessTester for demo test

3.6. 测试

一共设计到3张表,初始状态下,库存storage_tbl存储了100个库存,订单表order_tbl为空,账户表account_tbl有999元。测试类模拟了用户购买了2件200元的商品。

3.6.1. 正常执行

如果一切正常,那么:

1、account_tbl表账户余额为999 - 200*2 = 599元

2、order_tbl表会生成一个订单

3、storage_tbl表的库存为100 - 2 = 98

测试结果如下图:

image-20231023010711440

3.6.2. 模拟异常发生

在业务方法上加了@GlobalTransactional注解,如果分布式事务生效,那么在发生异常Exception时,3张表的数据都会回滚,值还是初始值,即:

1、account_tbl表为999元

2、order_tbl是空的

3、storage_tbl是100件

添加模拟发生异常的代码:

image-20231023011144154

查看测试结果如下图:

观察到控制台发生了一场,且数据库中3张表的数据没有变动。

image-20231023011713581

3.6.3. 原理简述

全部3个微服务全部debug启动,且基于架构图,Account服务是最后调用的,在该服务上打上一个断点。然后去观察undo_log表中的内容。注意超时时间哦。

1、打上断点

在io.seata.samples.dubbo.service.impl.OrderServiceImpl#create的最后位置打上断点

2、观察undo_log表

image-20231023012240702

备注:刚好3条记录,对应3张表变更前后的内容;blob的内容查看需要再navicat中设置一下;然后复制格式化成json。

3、观察3张表的数据

下面是账户余额表account_tbl变更前后的数据情况(json格式化后):

{"@class": "io.seata.rm.datasource.undo.BranchUndoLog","xid": "172.17.0.4:8091:2151716199","branchId": 2151716201,"sqlUndoLogs": ["java.util.ArrayList",[{"@class": "io.seata.rm.datasource.undo.SQLUndoLog","sqlType": "UPDATE","tableName": "account_tbl","beforeImage": {"@class": "io.seata.rm.datasource.sql.struct.TableRecords","tableName": "account_tbl","rows": ["java.util.ArrayList",[{"@class": "io.seata.rm.datasource.sql.struct.Row","fields": ["java.util.ArrayList",[{"@class": "io.seata.rm.datasource.sql.struct.Field","name": "id","keyType": "PRIMARY_KEY","type": 4,"value": 2},{"@class": "io.seata.rm.datasource.sql.struct.Field","name": "money","keyType": "NULL","type": 4,"value": 999}]]}]]},"afterImage": {"@class": "io.seata.rm.datasource.sql.struct.TableRecords","tableName": "account_tbl","rows": ["java.util.ArrayList",[{"@class": "io.seata.rm.datasource.sql.struct.Row","fields": ["java.util.ArrayList",[{"@class": "io.seata.rm.datasource.sql.struct.Field","name": "id","keyType": "PRIMARY_KEY","type": 4,"value": 2},{"@class": "io.seata.rm.datasource.sql.struct.Field","name": "money","keyType": "NULL","type": 4,"value": 599}]]}]]}}]]
}

下面是订单表order_tbl:

{"@class":"io.seata.rm.datasource.undo.BranchUndoLog","xid":"172.17.0.4:8091:2151716242","branchId":2151716245,"sqlUndoLogs":["java.util.ArrayList",[{"@class":"io.seata.rm.datasource.undo.SQLUndoLog","sqlType":"INSERT","tableName":"order_tbl","beforeImage":{"@class":"io.seata.rm.datasource.sql.struct.TableRecords$EmptyTableRecords","tableName":"order_tbl","rows":["java.util.ArrayList",[]]},"afterImage":{"@class":"io.seata.rm.datasource.sql.struct.TableRecords","tableName":"order_tbl","rows":["java.util.ArrayList",[{"@class":"io.seata.rm.datasource.sql.struct.Row","fields":["java.util.ArrayList",[{"@class":"io.seata.rm.datasource.sql.struct.Field","name":"id","keyType":"PRIMARY_KEY","type":4,"value":6},{"@class":"io.seata.rm.datasource.sql.struct.Field","name":"user_id","keyType":"NULL","type":12,"value":"U100001"},{"@class":"io.seata.rm.datasource.sql.struct.Field","name":"commodity_code","keyType":"NULL","type":12,"value":"C00321"},{"@class":"io.seata.rm.datasource.sql.struct.Field","name":"count","keyType":"NULL","type":4,"value":2},{"@class":"io.seata.rm.datasource.sql.struct.Field","name":"money","keyType":"NULL","type":4,"value":400}]]}]]}}]]}

下面是库存表storage_tbl:

{"@class":"io.seata.rm.datasource.undo.BranchUndoLog","xid":"172.17.0.4:8091:2151716242","branchId":2151716243,"sqlUndoLogs":["java.util.ArrayList",[{"@class":"io.seata.rm.datasource.undo.SQLUndoLog","sqlType":"UPDATE","tableName":"storage_tbl","beforeImage":{"@class":"io.seata.rm.datasource.sql.struct.TableRecords","tableName":"storage_tbl","rows":["java.util.ArrayList",[{"@class":"io.seata.rm.datasource.sql.struct.Row","fields":["java.util.ArrayList",[{"@class":"io.seata.rm.datasource.sql.struct.Field","name":"id","keyType":"PRIMARY_KEY","type":4,"value":2},{"@class":"io.seata.rm.datasource.sql.struct.Field","name":"count","keyType":"NULL","type":4,"value":100}]]}]]},"afterImage":{"@class":"io.seata.rm.datasource.sql.struct.TableRecords","tableName":"storage_tbl","rows":["java.util.ArrayList",[{"@class":"io.seata.rm.datasource.sql.struct.Row","fields":["java.util.ArrayList",[{"@class":"io.seata.rm.datasource.sql.struct.Field","name":"id","keyType":"PRIMARY_KEY","type":4,"value":2},{"@class":"io.seata.rm.datasource.sql.struct.Field","name":"count","keyType":"NULL","type":4,"value":98}]]}]]}}]]}

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

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

相关文章

2023高频前端面试题(含答案)

一、简单页面1、CSS选择器样式优先级2、CSS实现三列布局&#xff08;左右固定宽度&#xff0c;中间自适应&#xff09; &#xff08;1&#xff09;CSS浮动 第一个float:left&#xff0c;第二个float:right&#xff0c;第三个设置margin-left和margin-right &#xff08;2&#…

无纸化办公小程序数据交互、wxs的使用

前言 很多同志们再写小程序的过程中&#xff0c;不知道该怎么发起HTTP请求到后端&#xff0c;在Web环境中发起HTTPS请求是很常见的&#xff0c;但是微信小程序是腾讯内部的产品&#xff0c;不能直接打开一个外部的链接。例如&#xff0c;在微信小程序中不能直接打开www.taobao…

ASRPRO语音识别模块

ASRPRO语音识别模块 SOFT IIC 与PCA9685模块通信 pca9685 iic通信 地址位 ADDR<<1|0 左移一位 #define I2C_WRITE 0 #define I2C_READ 1 否则通信地址错误 asrpro 通过UART与电脑连接&#xff0c;可以进行简单的交互 将STM32作为接口扩展&#xff0c;通过SPI或I…

Seata学习

Seata Seata 是一款开源的分布式事务解决方案&#xff0c;致力于在微服务架构下提供高性能和简单易用的分布式事务服务。 官网地址&#xff1a;https://seata.io/zh-cn/index.html 为什么会产生分布式事务&#xff1f; 示例&#xff1a;用户下单后需要创建订单&#xff0c;同时…

DDR电源硬件设计要点

一、DDR电源简介 1. 电源 DDR的电源可以分为三类: a、主电源VDD和VDDQ,主电源的要求是VDDQ=VDD,VDDQ是给IO buffer供电的电源,VDD是给但是一般的使用中都是把VDDQ和VDD合成一个电源使用。 有的芯片还有VDDL,是给DLL供电的,也和VDD使用同一电源即可。电源设计时,需要考…

最短路相关笔记

Floyd Floyd 算法&#xff0c;是一种在图中求任意两点间最短路径的算法。 Floyd 算法适用于求解无负边权回路的图。 时间复杂度为 O ( n 3 ) O(n^3) O(n3)&#xff0c;空间复杂度 O ( n 2 ) O(n^2) O(n2)。 对于两点 ( i , j ) (i,j) (i,j) 之间的最短路径&#xff0c;有…

如何让ChatGPT生成图片?

目录 一、那么如何解决让ChatGPT具有画图能力的问题呢&#xff1f; 二、那ChatGPT为什么能生成图片呢&#xff1f; 我们都知道ChatGPT只是个纯文本的AI模型&#xff0c;不具备画图能力。它可以生成文本&#xff0c;但如果让他生成图片就会显示如下的声明&#xff1a; 但通过本…

图像信号处理板设计原理图:2-基于6U VPX的双TMS320C6678+Xilinx FPGA K7 XC7K420T的图像信号处理板

综合图像处理硬件平台包括图像信号处理板2块&#xff0c;视频处理板1块&#xff0c;主控板1块&#xff0c;电源板1块&#xff0c;VPX背板1块。 一、板卡概述 图像信号处理板包括2片TI 多核DSP处理器-TMS320C6678&#xff0c;1片Xilinx FPGA XC7K420T-1FFG1156&#xff0c;1片X…

strcpy函数

文章目录 strcpy函数描述函数使用总结目标空间为什么必须可变&#xff1f;模拟实现 strcpy函数描述 重点&#xff1a;including the terminating null character (and stopping at that point).意为拷贝的值包括停止字符 传参时第一个参数为要拷贝参数&#xff0c;第二个参数为…

游戏盾如何有效防护DDoS

从进入计算机时代以来&#xff0c;DDoS攻击一直是网络世界中的一大威胁&#xff0c;让无数服务陷入瘫痪。这种攻击的原理非常简单&#xff1a;攻击者使用大量的僵尸主机或蠕虫病毒&#xff0c;向目标服务器发送海量请求&#xff0c;迅速耗尽服务器的资源&#xff0c;使其无法继…

某全球领先的芯片供应商:优化数据跨网交换流程,提高安全管控能力

1、客户介绍 某全球领先的芯片供应商&#xff0c;成立于2005年&#xff0c;总部设于北京&#xff0c;在国内上海、深圳、合肥等地及国外多个国家和地区均设有分支机构和办事处&#xff0c;致力于为客户提供更优质、便捷的服务。 2、建设背景 该公司基于网络安全管理的需求&am…

Datawhale学习笔记AI +新能源:电动汽车充电站充电量预测2

在飞浆平台上成功运行出pandas-profiling啦~ 首先一键安装 pip install ydata_profiling然后演示&#xff0c;可以生成一个网页对数据有一个比较好的理解 import numpy as np import pandas as pd from ydata_profiling import ProfileReporttrain_power pd.read_csv(/home/…

【论文阅读】以及部署BEVFusion: A Simple and Robust LiDAR-Camera Fusion Framework

BEVFusion: A Simple and Robust LiDAR-Camera Fusion Framework BEVFusion&#xff1a;一个简单而强大的LiDAR-相机融合框架 NeurIPS 2022 多模态传感器融合意味着信息互补、稳定&#xff0c;是自动驾驶感知的重要一环&#xff0c;本文注重工业落地&#xff0c;实际应用 融…

Flutter的Don‘t use ‘BuildContext‘s across async gaps警告解决方法

文章目录 问题有问题的源码 问题原因问题分析Context的含义BuildContext的作用特殊情况 解决方法 问题 Flutter开发中遇到Don’t use BuildContext’s across async gaps警告 有问题的源码 if (await databaseHelper.isDataExist(task.title)) {showDialog(context: context,…

想要精通算法和SQL的成长之路 - 找到最终的安全状态

想要精通算法和SQL的成长之路 - 找到最终的安全状态 前言一. 找到最终的安全状态1.1 初始化邻接图1.2 构建反向邻接图1.3 BFS遍历1.4 完整代码 前言 想要精通算法和SQL的成长之路 - 系列导航 一. 找到最终的安全状态 原题链接 我们从题目中可以看出来&#xff1a; 出度为0的…

面向对象(基础)特征一:封装性(encapsulation)

文章目录 一、介绍&#xff08;1&#xff09;封装性&#xff08;2&#xff09;权限修饰符 二、案例&#xff08;1&#xff09;案例1 三、练习&#xff08;1&#xff09;练习1&#xff08;2&#xff09;练习2&#xff08;3&#xff09;练习3&#xff08;4&#xff09;练习4 面向…

我做不到受每个人喜欢

我做不到受每个人喜欢 我想描述一下昨天发生争吵后我个人的观点&#xff0c;希望能够重新呈现出一种积极的态度。 首先&#xff0c;让我简要梳理一下事件的经过&#xff0c;当天我像往常一样去另一个宿舍找人聊天&#xff0c;可能因为说话声音有点大&#xff0c;坐在我后面的那…

运维:mysql常用的服务器状态命令

目录 1、查询当前服务器运行的进程 2、查询最大链接数 3、查询当前链接数 4、展示当前正在执行的sql语句 5、查询当前MySQL当中记录的慢查询条数 6、展示Mysql服务器从启动到现在持续运行的时间 7、查询数据库存储占用情况 8、查询服务器启动以来的执行查询的总次数 9…

vue3 使用 elementUi: ./lib/theme-chalk/index.css is not exported from package

目录 1. 在 vue3 中使用 element-ui2. 如果启动报错&#xff1a;Module not found: Error: Package path ./lib/theme-chalk/index.css is not exported from package 1. 在 vue3 中使用 element-ui 在 vue3 中使用 element-ui&#xff0c;我们的流程一般是这样的&#xff1a;…

Spark--经典SQL50题

目录 连接数据库准备工作 1、查询"01"课程比"02"课程成绩高的学生的信息及课程分数 2、查询"01"课程比"02"课程成绩低的学生的信息及课程分数 3、查询平均成绩大于等于60分的同学的学生编号和学生姓名和平均成绩 4、查询平均成绩…