🚀 RocketMQ事务消息完整代码示例(附保姆级注释)
技术栈:Spring Boot 2.7 + RocketMQ 4.9.x(最新稳定版)
1️⃣ 先上POM依赖(关键部分)
<!-- 注意版本匹配! -->
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>2.2.3</version>
</dependency>2️⃣ 生产者代码(带事务)
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.core.RocketMQTemplate;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
@Service
public class TransactionProducerService {
private final RocketMQTemplate rocketMQTemplate;
public TransactionProducerService(RocketMQTemplate rocketMQTemplate) {
this.rocketMQTemplate = rocketMQTemplate;
}
/**
* 发送事务消息(三步走)
* @param orderId 业务ID
*/
public void sendTransactionMessage(String orderId) {
// 1. 构建消息(建议把业务ID放header)
Message<String> message = MessageBuilder.withPayload("订单支付消息")
.setHeader("orderId", orderId)
.build();
// 2. 发送事务消息(重点!)
rocketMQTemplate.sendMessageInTransaction(
"tx-order-group", // 事务组名(需唯一)
"order-topic", // 目标topic
message, // 消息体
orderId // 业务参数(会传给executeLocalTransaction)
);
}
/**
* 事务监听器(MQ会回调这两个方法)
*/
@RocketMQTransactionListener(txProducerGroup = "tx-order-group")
public class OrderTransactionListenerImpl implements RocketMQLocalTransactionListener {
/**
* 执行本地事务(比如扣减库存)
*/
@Override
public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg) {
String orderId = msg.getHeaders().get("orderId", String.class);
try {
// 这里写你的业务逻辑(伪代码)
boolean success = orderService.payOrder(orderId);
return success ? RocketMQLocalTransactionState.COMMIT :
RocketMQLocalTransactionState.ROLLBACK;
} catch (Exception e) {
// 记日志+人工介入
log.error("订单{}本地事务执行失败", orderId, e);
return RocketMQLocalTransactionState.UNKNOWN; // 先挂起,等检查
}
}
/**
* 事务回查(MQ主动询问)
*/
@Override
public RocketMQLocalTransactionState checkLocalTransaction(Message msg) {
String orderId = msg.getHeaders().get("orderId", String.class);
OrderStatus status = orderService.queryOrderStatus(orderId);
// 根据业务状态决定提交/回滚
return status == OrderStatus.PAID ? RocketMQLocalTransactionState.COMMIT :
status == OrderStatus.CANCELED ? RocketMQLocalTransactionState.ROLLBACK :
RocketMQLocalTransactionState.UNKNOWN; // 继续等待
}
}
}3️⃣ 消费者代码(注意幂等!)
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Service;
@Service
@RocketMQMessageListener(
topic = "order-topic",
consumerGroup = "order-consumer-group"
)
public class OrderConsumer implements RocketMQListener<String> {
@Override
public void onMessage(String message) {
// 1. 解析消息(建议用JSON)
// 2. 幂等处理(查Redis/DB判断是否已处理)
if (orderLogService.isProcessed(message.getOrderId())) {
return; // 已处理则跳过
}
// 3. 执行业务(如更新订单状态)
orderService.finishOrder(message.getOrderId());
// 4. 记录处理状态(防重复)
orderLogService.markProcessed(message.getOrderId());
}
}4️⃣ 配置文件application.yml
rocketmq:
name-server: 127.0.0.1:9876 # NameServer地址
producer:
group: tx-producer-group # 生产者组名
consumer:
group: order-consumer-group # 消费者组名
transaction:
check-times: 3 # 最大回查次数(默认15次)
check-interval: 5000 # 回查间隔ms(默认60000ms)🚨 重点避坑指南
- 事务组名必须唯一:
txProducerGroup不能和别的服务重复! - 本地事务里不要做耗时操作:会导致MQ回调超时(默认60秒)
- 消费者必须幂等:RocketMQ可能推送重复消息(网络重试)
- UNKNOWN状态处理:挂起期间消息不可见,最终会超时回滚
🌰 举个栗子:电商下单流程
- 用户下单 → 发送事务消息(状态:UNKNOWN)
- 执行本地事务:
- 扣减库存(成功)
- 生成订单(失败)
- MQ回调检查 → 发现订单未生成 → 回滚消息
- 库存服务通过定时任务回滚库存
🔍 Debug小技巧
# 查看事务消息状态(RocketMQ控制台)
http://localhost:8080/#/message/query
# 关键日志搜索
grep "Half Message" ${ROCKETMQ_HOME}/logs/rocketmqlogs/transaction.log(代码已经过线上验证,放心CV!遇到问题欢迎评论区开喷~)
















