RocketMQ整合SpringBoot事务消息

RocketMQ事务消息流程

发送半消息:生产者首先发送一个半消息(即预消息)到 Broker。半消息的作用是先占据一个位置,但不会被消费者消费,直到事务提交成功。

执行本地事务 :Broker 接收到半消息并确认后,回调生产者的 executeLocalTransaction 方法执行本地事务。

提交事务状态:根据本地事务的执行结果,生产者向 Broker 提交事务状态(COMMIT、ROLLBACK 或 UNKNOWN)。如果提交成功,半消息会被转换为正式消息,并且可以被消费者消费;如果回滚,半消息会被删除。

事务状态回查 :如果 Broker 未能及时收到生产者的提交状态,或者收到的是 UNKNOWN 状态,Broker 会定期回调生产者的 checkLocalTransaction 方法以确定事务的最终状态。

消费者消费消息:当事务消息被提交后,消费者可以正常消费这条消息。消费者接收并处理消息的逻辑与普通消息相同。

复制代码
package com.example.springbootrocketmq.controller;

import com.example.springbootrocketmq.producer.RocketMQTransactionProducerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 控制器类,用于触发事务消息发送
 * @author hrui
 * @date 2024/8/4 2:40
 */
@RestController
public class TransactionController {

    @Autowired
    private RocketMQTransactionProducerService producerService;

    @GetMapping("/send")
    public String sendTransactionMessage() {
        producerService.sendMessageInTransaction("transaction-topic", "事务消息负载");
        return "事务消息已发送";
    }
}

package com.example.springbootrocketmq.producer;

import com.example.springbootrocketmq.pojo.User;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.apache.rocketmq.spring.support.RocketMQHeaders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;

import java.util.UUID;

/**
 * 事务消息生产者服务类
 * @author hrui
 * @date 2024/8/4 2:40
 */
@Service
public class RocketMQTransactionProducerService {

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    /**
     * 发送事务消息
     * @param topic 消息主题
     * @param msgBody 消息内容
     */
    public void sendMessageInTransaction(String topic, String msgBody) {
        //构建消息,指定消息体和事务ID
        //Message<String> message = MessageBuilder.withPayload(msgBody).build();
        Message<String> message = MessageBuilder.withPayload(msgBody)
                .setHeader(RocketMQHeaders.TRANSACTION_ID, UUID.randomUUID().toString())//可以在MQ消息头里放 一个key  一个value
                .build();

        //发送事务消息,rocketMQTemplate会触发事务监听器的执行
        //1.发送半消息
        //第一个参数可以传topic 也可以传topic+tag  第三个参数是业务参数(本地回调时候可以访问到,会传过来)
        SendResult sendResult = rocketMQTemplate.sendMessageInTransaction(topic+":"+"tags", message, new User("hrui", 18, "杭州"));//第三个是业务参数  业务里要带过去什么就带什么
        System.out.println("发送结果: " + sendResult);
    }
}

package com.example.springbootrocketmq.listener;

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.RocketMQUtil;
import org.springframework.messaging.Message;
import org.springframework.messaging.converter.StringMessageConverter;
import org.springframework.stereotype.Component;

/**
 * 事务监听器类,用于管理本地事务状态
 * @author hrui
 * @date 2024/8/4 2:41
 */
@RocketMQTransactionListener(rocketMQTemplateBeanName = "rocketMQTemplate")
public class RocketMQTransactionListenerImpl implements RocketMQLocalTransactionListener {

    @Override
    public RocketMQLocalTransactionState executeLocalTransaction(Message message, Object o) {
        // 将Spring的message转为RocketMQ的Message
        org.apache.rocketmq.common.message.Message rocketMsg = RocketMQUtil.convertToRocketMessage(new StringMessageConverter(), "UTF-8", o.toString(), message);
        // 执行本地事务
        System.out.println("执行本地事务: " + new String(rocketMsg.getBody()));
        try {
            // 执行实际的本地事务逻辑
            boolean success = true; // 执行本地事务(例如数据库操作)
            if (success) {
                return RocketMQLocalTransactionState.COMMIT;
            } else {
                return RocketMQLocalTransactionState.ROLLBACK;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return RocketMQLocalTransactionState.UNKNOWN;
        }
    }

    @Override
    public RocketMQLocalTransactionState checkLocalTransaction(Message message) {
        // 检查事务状态
        System.out.println("检查本地事务: " + new String(message.getPayload().toString()));
        try {
            // 检查本地事务执行结果
            boolean success = true; // 检查本地事务状态(例如查询数据库)
            if (success) {
                return RocketMQLocalTransactionState.COMMIT;
            } else {
                return RocketMQLocalTransactionState.ROLLBACK;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return RocketMQLocalTransactionState.UNKNOWN;
        }
    }
}

消费者

复制代码
package com.example.springbootrocketmq.consumer;

import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Component;

/**
 * 消费者服务类,用于消费来自主题的消息
 * @author hrui
 * @date 2024/8/4 2:42
 */
@Component
@RocketMQMessageListener(topic = "transaction-topic", consumerGroup = "transaction-consumer-group")
public class RocketMQTransactionConsumerService implements RocketMQListener<String> {

    @Override
    public void onMessage(String message) {
        System.out.println("接收到事务消息: " + message);
    }
}

测试时候是在一个应用中做的测试,application.properties 加了ACL访问控制

复制代码
rocketmq.name-server=xxx.xxx.xxx:9876
rocketmq.producer.group=mq_producer_group_test
rocketmq.producer.access-key=xxxxx
rocketmq.producer.secret-key=xxxxx


rocketmq.consumer.access-key=xxxxx
rocketmq.consumer.secret-key=xxxxx
相关推荐
Z_W_H_2 小时前
【SpringBoot】 整合MyBatis+Postgresql
java·spring boot·后端
麦兜*3 小时前
【SpringBoot 】Spring Boot OAuth2 六大安全隐患深度分析报告,包含渗透测试复现、漏洞原理、风险等级及完整修复方案
java·jvm·spring boot·后端·spring·系统架构
Code季风4 小时前
Spring Bean的生命周期详解
java·spring boot·spring
小咪一会5 小时前
速学 RocketMQ
学习·rocketmq·java-rocketmq
万能小锦鲤5 小时前
《Java EE与中间件》实验三 基于Spring Boot框架的购物车
java·spring boot·mysql·实验报告·购物车·文档资源·java ee与中间件
麦兜*5 小时前
【Spring Boot】Spring Boot 4.0 的颠覆性AI特性全景解析,结合智能编码实战案例、底层架构革新及Prompt工程手册
java·人工智能·spring boot·后端·spring·架构
全栈凯哥6 小时前
20.缓存问题与解决方案详解教程
java·spring boot·redis·后端·缓存
源码云商6 小时前
基于 SpringBoot + Vue 的 IT 技术交流和分享平台的设计与实现
vue.js·spring boot·后端
ladymorgana14 小时前
【spring boot】三种日志系统对比:ELK、Loki+Grafana、Docker API
spring boot·elk·grafana
程序员秘密基地15 小时前
基于html,css,vue,vscode,idea,,java,springboot,mysql数据库,在线旅游,景点管理系统
java·spring boot·mysql·spring·web3