前言
上篇文章,介绍了RocketMQ消息类型支持事务消息,常见用在分布式系统中,保证数据的一致性。接下来一起去走进 TransactionMQProducer、TransactionListener俩个核心类
一.基于apache-rocketmq事务消息的实现
(1) pom.xml配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--lombok插件 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<!--RocketMQ-->
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.3.0</version>
</dependency>
(2)事务消息生产者配置
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.TransactionMQProducer;
import org.springframework.stereotype.Component;
@Component
public class PayProducer {
/**
* 生产组,消费者通过订阅发布,在同一个组内
*/
private String producerGroup = "pay_group";
/**
* 端口
*/
private String nameServer = "127.0.0.1:9876";
//事务监听,其中rocketMQLisenter实现TransactionListener接口
private RocketMQLisenter rocketMQLisenter;
//事务消息生产者配置
private TransactionMQProducer producer;
public PayProducer() {
producer = new TransactionMQProducer(producerGroup);
rocketMQLisenter = new RocketMQLisenter();
// 指定nameServer地址,多个地址之间以 ; 隔开
producer.setNamesrvAddr(nameServer);
producer.setTransactionListener(rocketMQLisenter);
start();
}
public TransactionMQProducer getProducer() {
return producer;
}
/**
* 对象在使用之前必须调用一次,并且只能初始化一次
*/
public void start() {
try {
this.producer.start();
} catch (MQClientException e) {
e.printStackTrace();
}
}
/**
* 一般在应用上下文,使用上下文监听器,进行关闭
*/
public void shutdown() {
producer.shutdown();
}
}
(3)事务监听器接口实现
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.producer.LocalTransactionState;
import org.apache.rocketmq.client.producer.TransactionListener;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.common.message.MessageExt;
@Slf4j
public class RocketMQLisenter implements TransactionListener {
@Override
public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
log.info("=========本地事务开始执行=============");
String message = new String(msg.getBody());
int type = 0;
// 事务消息id,唯一
String tid = msg.getTransactionId();
//todo 为了解决重复消息《==》幂等性,可以将tid放入redis,并设置状态,消费端,每次从redis中获取事务id,根据状态并判断是否被消费过
//模拟执行本地事务begin====