Transactional Message:通过两阶段提交保证本地事务与消息发送的一致性(如订单支付成功后发送物流消息)
在SpringBoot中通过RocketMQTemplate发送事务消息,需结合事务监听器实现本地事务与消息的一致性,通常是sendMessageInTransaction。使用这个方法需要以下几个步骤:
创建事务监听器:实现RocketMQLocalTransactionListener接口,重写executeLocalTransaction和checkLocalTransaction方法。executeLocalTransaction用于执行本地事务,checkLocalTransaction用于事务回查。
注入事务监听器:通过@RocketMQTransactionListener注解将监听器注入Spring容器,并指定对应的RocketMQTemplate实例(如果有多个的话)。
使用RocketMQTemplate发送事务消息:调用sendMessageInTransaction方法,传入topic、消息内容、以及本地事务的参数。
需要注意的是,事务消息的发送需要确保本地事务的执行结果能够正确反馈给RocketMQ,以便Broker决定提交还是回滚半事务消息。此外,事务监听器的实现需要处理本地事务的执行和回查逻辑。
- 定义事务监听器(核心)
实现RocketMQLocalTransactionListener接口,重写本地事务执行和回查方法,通过@RocketMQTransactionListener注解注入Spring容器。
java
import org.apache.rocketmq.spring.annotation.RocketMQTransactionListener;
import org.apache.rocketmq.spring.core.RocketMQLocalTransactionListener;
import org.apache.rocketmq.spring.core.RocketMQLocalTransactionState;
import org.springframework.messaging.Message;
@RocketMQTransactionListener(
rocketMQTemplateBeanName = "rocketMQTemplate" // 关联指定的RocketMQTemplate实例(默认可不填)
)
public class TransactionListenerImpl implements RocketMQLocalTransactionListener {
/**
* 执行本地事务
* @param msg 半事务消息
* @param arg 发送消息时传入的参数(可用于传递业务数据)
* @return 事务状态:COMMIT(提交)、ROLLBACK(回滚)、UNKNOWN(需要回查)
*/
@Override
public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg) {
try {
// 1. 执行业务逻辑(如数据库操作、订单创建等)
String orderId = (String) arg; // 从arg中获取业务参数
System.out.println("执行本地事务,订单ID:" + orderId);
// 2. 业务成功,返回COMMIT
return RocketMQLocalTransactionState.COMMIT;
} catch (Exception e) {
// 3. 业务失败,返回ROLLBACK
return RocketMQLocalTransactionState.ROLLBACK;
}
}
/**
* 事务回查(当Broker未收到本地事务结果时触发)
* @param msg 半事务消息
* @return 事务状态:COMMIT(提交)、ROLLBACK(回滚)、UNKNOWN(继续回查)
*/
@Override
public RocketMQLocalTransactionState checkLocalTransaction(Message msg) {
// 1. 检查本地事务执行结果(如查询数据库中订单状态)
String orderId = msg.getHeaders().get("ORDER_ID", String.class);
System.out.println("回查本地事务,订单ID:" + orderId);
// 2. 根据实际状态返回结果(示例:假设查询到订单已成功,返回COMMIT)
return RocketMQLocalTransactionState.COMMIT;
}
}
- 使用RocketMQTemplate发送事务消息
调用rocketMQTemplate.sendMessageInTransaction方法,传入事务消息参数(Topic、消息体、本地事务参数)。
java
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@Component
public class TransactionProducer {
@Resource
private RocketMQTemplate rocketMQTemplate;
/**
* 发送事务消息
* @param topic 消息主题(格式:"topic:tag",如"OrderTopic:create")
* @param orderId 业务参数(如订单ID,将传递给事务监听器)
*/
public void sendTransactionMessage(String topic, String orderId) {
// 1. 构建消息(可添加自定义头信息,用于回查)
org.springframework.messaging.Message<String> message = MessageBuilder
.withPayload("订单创建消息:" + orderId) // 消息体
.setHeader("ORDER_ID", orderId) // 自定义头信息(回查时使用)
.build();
// 2. 发送事务消息
// 参数:topic、消息对象、本地事务参数(会传递给executeLocalTransaction的arg)
rocketMQTemplate.sendMessageInTransaction(topic, message, orderId);
}
}
- 关键配置与注意事项
依赖与版本
确保rocketmq-spring-boot-starter和rocketmq-client版本匹配(推荐的2.3.1+5.3.0),避免版本冲突。
事务监听器与RocketMQTemplate绑定
若项目中有多个RocketMQTemplate实例(通过@ExtRocketMQTemplateConfiguration创建),需在@RocketMQTransactionListener中通过rocketMQTemplateBeanName指定对应的模板名称,确保监听器与生产者关联。
本地事务幂等性
由于事务回查可能多次触发,executeLocalTransaction和checkLocalTransaction方法需保证幂等性(如通过订单ID判断是否已处理)。
事务状态返回
executeLocalTransaction返回UNKNOWN时,Broker会在间隔时间后触发回查(默认60秒,可通过transactionCheckInterval配置),最多回查15次(默认,可通过transactionCheckMax配置)。
- 测试流程
调用TransactionProducer.sendTransactionMessage("OrderTopic", "123456")发送事务消息。
RocketMQ会先发送半事务消息(消费者不可见),然后执行executeLocalTransaction。
若返回COMMIT,半事务消息转为可见,消费者可消费;若返回ROLLBACK,消息被丢弃;若返回UNKNOWN,触发checkLocalTransaction回查。
通过以上步骤,即可基于RocketMQTemplate实现事务消息的发送,确保本地业务与消息传递的一致性。