在Spring中,我们要实现事务,一般通过@Transactional注解实现。这在引入RocketMQ之前没有问题,但是在引入了RocketMQ之后,如果消息发送之后的业务逻辑处理发生了异常的话,这时候消息已经发送出去了,就会导致业务的问题。

为了解决这一问题,RocketMQ引入了Transactional Message【事务消息】。

  1. 生产者向MQServer发送半消息【半消息:会存储进MQ Server,但是被标记为不能投递状态】
  2. 发送半消息成功,生产者实行本地事务
  3. 根据本地事务结果向MQ Server发送二次确认请求
  4. MQ Server根据接受到的消息投递或者丢弃消息
  5. 若在本地事务执行过程中缺少二次确认消息或生产者处于等待状态,MQ服务器将向同一组中的每个生产者发送检查消息,然后继续3,4的操作

PS:消息三态

  • Commit:提交事务信息,消费者可以消费此消息
  • Rollback:回滚事务消息,broker会删除这条消息,消费者不能消费
  • UNKNOWN:broker需要回查确认消息状态

代码实现

发送半消息

利用rocketMQTemplate类的sendMessageInTransaction实现半消息发送

第一个参数为txProducerGroup:就是group名称,根据业务自定义

第二次信息为destination:topic名称

第三个信息为message:消息体,利用MessageBuilder.withPayload构建

第四个信息为arg:业务对象,用于处理本地业务

代码如下:

// 发送半消息
rocketMQTemplate.sendMessageInTransaction(
"test-transactional",
"test-topic",
MessageBuilder.withPayload(
Demo.builder().demoId(1).remark("哈哈哈").build()
).setHeader(RocketMQHeaders.TRANSACTION_ID, UUID.randomUUID().toString()).build(),
forObject
);

实现RocketMQLocalTransactionListener接口

新建demoTransactionalListener类,继承RocketMQLocalTransactionListener接口,实现了两个方法

executeLocalTransaction:处理本地业务

checkLocalTransaction:MQ Server发送检查信息相应

添加@RocketMQTransactionListener注解,txProducerGroup属性值与半消息的txProducerGroup参数值相同

代码如下:

import org.apache.rocketmq.spring.annotation.RocketMQTransactionListener;
import org.apache.rocketmq.spring.core.RocketMQLocalTransactionListener;
import org.apache.rocketmq.spring.core.RocketMQLocalTransactionState;
import org.apache.rocketmq.spring.support.RocketMQHeaders;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders; @RocketMQTransactionListener(txProducerGroup = "test-transactional")
public class demoTransactionalListener implements RocketMQLocalTransactionListener {
/**
* 处理本地事务
*/
@Override
public RocketMQLocalTransactionState executeLocalTransaction(Message message, Object arg) {
// 消息头
MessageHeaders headers = message.getHeaders();
String transactionalId = (String) headers.get(RocketMQHeaders.TRANSACTION_ID); // arg:sendMessageInTransaction方法的第四个参数,用于处于本地业务 try {
// 本地业务
return RocketMQLocalTransactionState.COMMIT;
} catch (Exception e) {
return RocketMQLocalTransactionState.ROLLBACK;
}
} /**
* 若在本地事务执行过程中缺少二次确认消息或生产者处于等待状态
* MQ Server将向同一组中的每个生产者发送检查消息
*/
@Override
public RocketMQLocalTransactionState checkLocalTransaction(Message message) { try {
// 检查
return RocketMQLocalTransactionState.COMMIT;
} catch (Exception e) {
return RocketMQLocalTransactionState.ROLLBACK;
}
}
}

PS:MQ Server发送检查:可以通过新建一个表,记录本地业务成功或者失败,然后检查相应只需要查一下数据就可以了

Spring Cloud Alibaba学习笔记(11) - RocketMQ事务消息的更多相关文章

  1. Spring Cloud Alibaba学习笔记(1) - 整合Spring Cloud Alibaba

    Spring Cloud Alibaba从孵化器版本毕业:https://github.com/alibaba/spring-cloud-alibaba,记录一下自己学习Spring Cloud Al ...

  2. Spring Cloud Alibaba学习笔记(14) - Spring Cloud Stream + RocketMQ实现分布式事务

    发送消息 在Spring消息编程模型下,使用RocketMQ收发消息 一文中,发送消息使用的是RocketMQTemplate类. 在集成了Spring Cloud Stream之后,我们可以使用So ...

  3. Spring Cloud Alibaba学习笔记

    引自B站楠哥:https://space.bilibili.com/434617924 一.创建父工程 创建父工程hello-spring-cloud-alibaba Spring Cloud Ali ...

  4. Spring Cloud Alibaba学习笔记(15) - 整合Spring Cloud Gateway

    Spring Cloud Gateway 概述 Spring Cloud Gateway 是 Spring Cloud 的一个全新项目,该项目是基于Netty.Reactor以及WEbFlux构建,它 ...

  5. Spring Cloud Alibaba学习笔记(3) - Ribbon

    1.手写一个客户端负载均衡器 在了解什么是Ribbon之前,首先通过代码的方式手写一个负载均衡器 RestTemplate restTemplate = new RestTemplate(); // ...

  6. Spring Cloud Alibaba学习笔记(22) - Nacos配置管理

    目前业界流行的统一配置管理中心组件有Spring Cloud Config.Spring Cloud Alibaba的Nacos及携程开源的Apollo,本文将介绍Nacos作为统一配置管理中心的使用 ...

  7. Spring Cloud Alibaba学习笔记(2) - Nacos服务发现

    1.什么是Nacos Nacos的官网对这一问题进行了详细的介绍,通俗的来说: Nacos是一个服务发现组件,同时也是一个配置服务器,它解决了两个问题: 1.服务A如何发现服务B 2.管理微服务的配置 ...

  8. Spring Cloud Alibaba学习笔记(10) - Spring消息编程模型下,使用RocketMQ收发消息

    编写生产者 集成 添加依赖 <dependency> <groupId>org.apache.rocketmq</groupId> <artifactId&g ...

  9. Spring Cloud Alibaba学习笔记(12) - 使用Spring Cloud Stream 构建消息驱动微服务

    什么是Spring Cloud Stream 一个用于构建消息驱动的微服务的框架 应用程序通过 inputs 或者 outputs 来与 Spring Cloud Stream 中binder 交互, ...

随机推荐

  1. python接入微博第三方API之2接入用户登录和微博发布

    python接入微博第三方API之2接入用户登录和微博发布 # coding=utf-8 import requests import json import MySQLdb from datetim ...

  2. SUPERSOCKET.CLIENTENGINE 简单使用

    首先 引用 SuperSocket.ClientEngine.Core.dll和 SuperSocket.ClientEngine.Common.dll 然后 就可以使用ClientEngine了. ...

  3. svn服务端搭建

    本文介绍的是SVN的服务器端的搭建. 一.SVN服务器安装 1.     首先来下载和搭建SVN服务器,下载地址如下: http://subversion.apache.org/packages.ht ...

  4. 十九款web漏洞扫描工具

    1. Arachni Arachni是一款基于Ruby框架搭建的高性能安全扫描程序,适用于现代Web应用程序.可用于Mac.Windows及Linux系统的可移植二进制文件. Arachni不仅能对基 ...

  5. DataWorks2.0——DataStudio简单对比使用上手

    1.原先的数据管理去哪里了? 悬停在此图标上即可:  2.项目模式有何不同?

  6. python中的随机函数random的用法示例

    python中的随机函数random的用法示例 一.random模块简介 Python标准库中的random函数,可以生成随机浮点数.整数.字符串,甚至帮助你随机选择列表序列中的一个元素,打乱一组数据 ...

  7. 08点睛Spring MVC4.1-Spring MVC的配置(含自定义HttpMessageConverter)

    8.1 配置 Spring MVC的配置是通过继承WebMvcConfigurerAdapter类并重载其方法实现的; 前几个教程已做了得配置包括 01点睛Spring MVC 4.1-搭建环境 配置 ...

  8. 预训练中Word2vec,ELMO,GPT与BERT对比

    预训练 先在某个任务(训练集A或者B)进行预先训练,即先在这个任务(训练集A或者B)学习网络参数,然后存起来以备后用.当我们在面临第三个任务时,网络可以采取相同的结构,在较浅的几层,网络参数可以直接加 ...

  9. 常见问题:MySQL/排序

    MySQL的排序分为两种,通过排序操作和按索引扫描排序. 按索引顺序扫描是一种很高效的方式,但使用的条件较为严格,只有orderby语句使用索引最左前列,或where语句与orderby语句条件列组合 ...

  10. 高级UI-沉浸式设计

    关于沉浸式设计,在国内指的是Toolbar和系统状态栏相统一,而谷歌官方给出的沉浸式则是指整个界面为UI所用,而这里所说的沉浸式则是指的前者,涉及4.4和5.0及以上,4.4以下的Android做不出 ...