RocketMQ学习笔记:分布式事务
这是本人学习的总结,主要学习资料如下
- 马士兵教育
- rocketMq官方文档
目录
- 1、分布式事务的难题
- 2、解决方式
- 2.1、半事务消息和事务回查
- 2.2、代码样例
- 2.2.1、TransactionListener
- 2.2.2、TransactionMQProducer
- 2.2.3、MessageListenerConcurrently
- 2.2.4、流程图
1、分布式事务的难题
现有两个系统,A向B转钱。A系统扣钱和B系统加钱就应该属于同一个事务,任何一个失败都要回滚。两个系统之间唯一的通信方式就是RocketMQ。

以最朴素的想法,现在就有两个实现分布式事务的方案。但这两个都有比较大的不可靠性。
- A系统先扣钱再发送MQ:这样的弊端是无法确定消息有没有发送到MQ,或者消息有没有被MQ保存。总之这做法缺少一些回查的机制。
- A系统先发送MQ再扣钱:这样的弊端是发送消息后,A系统可能出现错误回滚。而B收到了消息就正常消费,完全不知道A那边出了问题。
2、解决方式
2.1、半事务消息和事务回查
半事务消息:半事务消息是指向RocketMQ发送一条消息,但这个消息只存放在CommitLog中,并不在ConsumeQueue展示。也就是说该消息被RocketMQ接收了,但是消费者却无法消费到这条消息。事务回查:在半事务消息发送成功后。A系统执行事务,如果成功则MQ将消息变成正常消息,失败则不发送消息。这里如果业务太复杂还不能确定事务是否完成的话,还可以发送UNKNOWN给MQ,这样MQ就会有定时器去检查事务是否完成。
RocketMQ会向生产者询问是否可以把半事务变成正常的消息让消费者可以消费到。在这篇文章的例子就是询问A系统扣款有没有扣成功。如果成功了那就让B系统消费消息。

所以呢,通过半事务消息和事务回查就能保证A系统和发送消息具有事务,即扣款失败则不发送消息,扣款成功则发送消息。所以半事务消息至少保证了生产者和MQ之间的原子性。MQ和消费者之间的原子性需要另外处理。
消费者需要保证幂等性,失败后重试,即使称为死信后也特殊处理等操作来保证事务。这个例子中B系统成功加钱的话那交易结束,如果尝试多次后还是失败,那就需要一个机制来通知A系统,让他把扣掉的钱加回去。
2.2、代码样例
2.2.1、TransactionListener
一个接口规范,我们需要实现这个接口来定义本地事务和事务回查。
就是本地事务具体执行,成功后怎么办,失败了怎么办。定时的事务回查如何检查事务有没有完成。这些东西都要定义在TransactionListener的实现中。
TransactionListener transactionListener = new TransactionListener() {@Overridepublic LocalTransactionState executeLocalTransaction(Message message, Object o) {// 执行本地事务,A扣100块// 如果成功// return LocalTransactionState.COMMIT_MESSAGE;// 如果失败// return LocalTransactionState.ROLLBACK_MESSAGE;//或者业务比较复杂,不想在这个阶段就关闭事务,可以返回Unknown,之后就需要MQ定时事务回查return LocalTransactionState.UNKNOW;}@Override// 事务回查,默认一分钟一次public LocalTransactionState checkLocalTransaction(MessageExt messageExt) {System.out.println("事务回查, " + new SimpleDateFormat("yyyyMMdd, HH:mm:ss").format(new Date()));// 如果成功// return LocalTransactionState.COMMIT_MESSAGE;// 如果失败// return LocalTransactionState.ROLLBACK_MESSAGE;// 业务比较长,还不确定成功或失败,返回unknown,下次再查return LocalTransactionState.UNKNOW;}};
2.2.2、TransactionMQProducer
半事务消息的生产者,在DefaultMQProducer的基础上新增了一个重要的参数,类型是ExecutorService。这个线程池是用来生产线程去完成事务回查。
但是事务回查的逻辑不需要定义在线程的run()方法中,这一部分放在TransactionListener中。
TransactionMQProducer producer = new TransactionMQProducer("transaction_producer");producer.setNamesrvAddr("localhost:9876");// build a thread pool used to for MQ to call back to check transactionExecutorService executorService = new ThreadPoolExecutor(2, 5, 100, TimeUnit.MINUTES, new ArrayBlockingQueue<>(10), (r) -> {Thread thread = new Thread(r);thread.setName("client-transaction-msg-check-thread");return thread;});producer.setExecutorService(executorService);producer.setTransactionListener(transactionListener);producer.start();try{Message msg = new Message("transaction_producer", null, "A give B 100 dollar".getBytes());SendResult sendResult = producer.sendMessageInTransaction(msg, null);}catch(Exception e) {// rollbackSystem.out.println("rollback");}producer.shutdown();
2.2.3、MessageListenerConcurrently
消费者部分就比较简单,只要listener是MessageListenerConcurrently就好。
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("transaction_consumer");
consumer.setNamesrvAddr("localhost:9876");
consumer.subscribe("TransactionalTopic", "*");
consumer.registerMessageListener(new MessageListenerConcurrently() {@Overridepublic ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext context) {try{for(MessageExt msg: list) {// simulate DB actionSystem.out.println("update B where transactionId" + msg.getTransactionId());System.out.println("Success consume msg: " + msg.getMsgId());}} catch (Exception e) {e.printStackTrace();System.out.println("Failed to consume meg, try more times");// means that failed to consume this msg. In next time will still consume this msg.return ConsumeConcurrentlyStatus.RECONSUME_LATER;}// means that success to consume this msg. In the next time will consume next msg.return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;}
});consumer.start();
while(true){
}
2.2.4、流程图

相关文章:
RocketMQ学习笔记:分布式事务
这是本人学习的总结,主要学习资料如下 马士兵教育rocketMq官方文档 目录 1、分布式事务的难题2、解决方式2.1、半事务消息和事务回查2.2、代码样例2.2.1、TransactionListener2.2.2、TransactionMQProducer2.2.3、MessageListenerConcurrently2.2.4、流程图 1、分布…...
单臂路由和三层交换机
目录 一.单臂路由 1.单臂路由的工作原理 2.单臂路由的配置 2.1画出拓扑图 2.2配置PC 2.3配置交换机 2.4配置路由器 2.5测试 二.三层交换机 1.三层交换机的概述 2.三层交换机的配置 2.1画出拓扑图 2.2配置PC 2.3配置二层交换机 2.4配置三层交换机 2.5测试 3.拓展 三.总结 一.…...
红岩思维导图的制作软件,分享4款热门的!
红岩思维导图的制作软件,分享4款热门的! 在当今信息爆炸的时代,思维导图作为一种有效的知识整理和思维拓展工具,受到了广大用户的青睐。红岩思维导图以其独特的风格和实用性,成为了许多人学习和工作中的得力助手。那么…...
es 集群开机自动启动
前面搭建了 es 集群,但是每次机器重启 都需要手动启动,很麻烦,所以这里介绍一下开机自动启动 首先使用 root 用户 es : 执行以下命令 vim /etc/init.d/elasticsearch 将以下内容 cv 进去 #!/bin/bash #chkconfig: 345 63 …...
使用JMeter从JSON响应的URL参数中提取特定值
在使用Apache JMeter进行API测试时,我们经常需要从JSON格式的响应中提取特定字段的值。这可以通过使用JMeter内置的JSON提取器和正则表达式提取器来完成。以下是一个具体的例子,展示了如何从一个JSON响应中提取rowId的值,同时处理字符串终止符…...
汽车电子行业知识:自动驾驶系统结构和各模块功能
文章目录 2.自动驾驶系统结构和各模块功能2.1.自动驾驶系统结构2.2.车载传感器2.2.1.激光雷达2.2.2.毫米波雷达2.2.3.超声波雷达2.2.4.摄像头2.2.5.GNSS2.2.6. IMU2.2.7.多传感器融合 2.3.各功能模块2.3.1.高精度地图2.3.2.定位2.3.3.感知2.3.4.决策2.3.5.规划2.3.6.控制2.3.7.…...
Oracle参数文件详解
1、参数文件的作用 参数文件用于存放实例所需要的初始化参数,因为多数初始化参数都具有默认值,所以参数文件实际存放了非默认的初始化参数。 2、参数文件类型 1)服务端参数文件,又称为 spfile 二进制的文件,命名规则…...
鸿蒙(HarmonyOS)Navigation如何实现多场景UI适配?
场景介绍 应用在不同屏幕大小的设备上运行时,往往有不同的UI适配,以聊天应用举例: 在窄屏设备上,联系人和聊天区在多窗口中体现。在宽屏设备上,联系人和聊天区在同一窗口体现。 要做好适配,往往需要开发…...
PTGui图像拼接实验
1 PTGui图像拼接实验 1.1 概述 图像拼接技术就是将数张有重叠部分的图像(可能是不同时间、不同视角或者不同传感器获得的)拼成一幅无缝的全景图或高分辨率图像的技术 图像配准(image alignment)和图像融合是图像拼接的两个关键…...
C++|类封装、类的分文件编写练习:设计立方体类、点和圆的关系
文章目录 练习案例1:设计立方体类CPP代码 练习案例2:点和圆的关系CPP代码 代码总结类的分文件编写 练习案例1:设计立方体类 设计立方体类(Cube) 求出立方体的面积和体积 分别用全局函数和成员函数判断两个立方体是否相等。 CPP代码 class Cube { pub…...
大数据开发扩展shell--尚硅谷shell笔记
大数据开发扩展shell 学习目标 1 熟悉shell脚本的原理和使用 2 熟悉shell的编程语法 第一节 Shell概述 1)Linux提供的Shell解析器有: 查看系统中可用的 shell [atguiguhadoop101 ~]$ cat /etc/shells /bin/sh/bin/bash/sbin/nologin/bin/dash/bin/t…...
考研数学|《1800》《1000》《880》《660》最佳搭配使用方法
直接说结论:基础不好先做1800、强化之前660,强化可选880/1000题。 首先,传统习题册存在的一个问题是题量较大,但难度波动较大。《汤家凤1800》和《张宇1000》题量庞大,但有些题目难度不够平衡,有些过于简单…...
【GameFramework框架内置模块】17、声音(Sound)
推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址QQ群:398291828大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦。 一、前言 【GameFramework框架】系列教程目录: https://blog.csdn.net/q764424567/article/details/1…...
视频记录历史播放位置效果
简介 每次打开页面视频从上一次的播放位置开始播放 利用lodash库做节流 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-sca…...
Request Response
简介 Request(请求) & Response(响应) 浏览器会向服务器发送请求数据,服务器也需要返回响应数据给浏览器,因此我们需要设置对应的类来代表请求数据和响应数据,且Servlet中的service方法就需…...
How to convert .py to .ipynb in Ubuntu 22.04
How to convert .py to .ipynb in Ubuntu 22.04 jupyter nbconvertp2j 最近看到大家在用jupyter notebook,我也试了一下,感觉还不错,不过,也遇到了一些问题,比方说,我有堆的.py文件,如果要一个一…...
【prometheus-operator】k8s监控集群外redis
1、部署exporter GitHub - oliver006/redis_exporter: Prometheus Exporter for Redis Metrics. Supports Redis 2.x, 3.x, 4.x, 5.x, 6.x, and 7.x redis_exporter-v1.57.0.linux-386.tar.gz # 解压 tar -zxvf redis_exporter-v1.57.0.linux-386.tar.gz # 启动 nohup ./redi…...
MySQL索引(图文并茂)
目录 一、索引的概念 二、索引的作用 三、创建索引的原则依据 四、索引的分类和创建 1、索引的分类 2、索引的创建 2.1 普通索引 2.1.1 直接创建索引 2.1.2 修改表方式创建 2.1.3 创建表的时候指定索引 2.2 唯一索引 2.2.1 直接创建唯一索引 2.2.2 修改表方式创建 …...
Redis 教程系列之Redis PHP 使用 Redis(十二)
PHP 使用 Redis 安装 开始在 PHP 中使用 Redis 前, 我们需要确保已经安装了 redis 服务及 PHP redis 驱动,且你的机器上能正常使用 PHP。 接下来让我们安装 PHP redis 驱动:下载地址为:https://github.com/phpredis/phpredis/releases。 P…...
JavaScript语法和数据类型
基础 JavaScript 借鉴了 Java 的大部分语法,但同时也受到 Awk、Perl 和 Python 的影响。 JavaScript 是区分大小写的,并使用 Unicode 字符集。举个例子,可以将单词 Frh(在德语中意思是“早”)用作变量名。 var Frh …...
label-studio的使用教程(导入本地路径)
文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...
Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...
AspectJ 在 Android 中的完整使用指南
一、环境配置(Gradle 7.0 适配) 1. 项目级 build.gradle // 注意:沪江插件已停更,推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...
基于IDIG-GAN的小样本电机轴承故障诊断
目录 🔍 核心问题 一、IDIG-GAN模型原理 1. 整体架构 2. 核心创新点 (1) 梯度归一化(Gradient Normalization) (2) 判别器梯度间隙正则化(Discriminator Gradient Gap Regularization) (3) 自注意力机制(Self-Attention) 3. 完整损失函数 二…...
解读《网络安全法》最新修订,把握网络安全新趋势
《网络安全法》自2017年施行以来,在维护网络空间安全方面发挥了重要作用。但随着网络环境的日益复杂,网络攻击、数据泄露等事件频发,现行法律已难以完全适应新的风险挑战。 2025年3月28日,国家网信办会同相关部门起草了《网络安全…...
BLEU评分:机器翻译质量评估的黄金标准
BLEU评分:机器翻译质量评估的黄金标准 1. 引言 在自然语言处理(NLP)领域,衡量一个机器翻译模型的性能至关重要。BLEU (Bilingual Evaluation Understudy) 作为一种自动化评估指标,自2002年由IBM的Kishore Papineni等人提出以来,…...
Spring AI Chat Memory 实战指南:Local 与 JDBC 存储集成
一个面向 Java 开发者的 Sring-Ai 示例工程项目,该项目是一个 Spring AI 快速入门的样例工程项目,旨在通过一些小的案例展示 Spring AI 框架的核心功能和使用方法。 项目采用模块化设计,每个模块都专注于特定的功能领域,便于学习和…...
沙箱虚拟化技术虚拟机容器之间的关系详解
问题 沙箱、虚拟化、容器三者分开一一介绍的话我知道他们各自都是什么东西,但是如果把三者放在一起,它们之间到底什么关系?又有什么联系呢?我不是很明白!!! 就比如说: 沙箱&#…...
《信号与系统》第 6 章 信号与系统的时域和频域特性
目录 6.0 引言 6.1 傅里叶变换的模和相位表示 6.2 线性时不变系统频率响应的模和相位表示 6.2.1 线性与非线性相位 6.2.2 群时延 6.2.3 对数模和相位图 6.3 理想频率选择性滤波器的时域特性 6.4 非理想滤波器的时域和频域特性讨论 6.5 一阶与二阶连续时间系统 6.5.1 …...
