事务型消息简介
- RocketMQ事务消息(Transactional Message) 是指应用本地事务和发送消息操作可以被定义到全局事务中,要么同时成功,要么同时失败。RocketMQ的事务消息提供类似 X/Open XA 的分布事务功能,通过事务消息能达到分布式事务的最终一致。
过程
- 阶段一(发送消息,执行本地事务,更行消息状态)
- 发送消息(half消息)
- 服务端响应消息写入结果
- 根据发送结果执行本地事务(如果写入失败,此时half消息对业务不可见,本地逻辑不执行)
- 根据本地事务状态执行Commit或者Rollback(Commit操作生成消息索引,消息对消费者可见)
- 阶段二(补偿)
- 对没有Commit/Rollback的事务消息(pending状态的消息),从服务端发起一次“回查”
- Producer收到回查消息,检查回查消息对应的本地事务的状态
- 根据本地事务状态,重新Commit或者Rollback
其中,补偿阶段用于解决消息Commit或者Rollback发生超时或者失败的情况。
- 详细过程可以到参考文档中
事务型消息的使用
@Component
public class MqProducer {
@Value("${mq.nameserver.addr}")
private String nameAddr;
@Value("${mq.topicname}")
private String topicName;
private TransactionMQProducer transactionMQProducer;
@PostConstruct
public void init() throws MQClientException {
transactionMQProducer=new TransactionMQProducer("transaction_producer_group");
transactionMQProducer.setNamesrvAddr(nameAddr);
transactionMQProducer.start();
transactionMQProducer.setTransactionListener(new TransactionListener() {
@Override
public LocalTransactionState executeLocalTransaction(Message message, Object args) {
try {
} catch (Exception e) {
e.printStackTrace();
return LocalTransactionState.ROLLBACK_MESSAGE;
}
return LocalTransactionState.COMMIT_MESSAGE;
}
@Override
public LocalTransactionState checkLocalTransaction(MessageExt msg) {
if(判断1){
return LocalTransactionState.COMMIT_MESSAGE;
}else if(判断2){
return LocalTransactionState.UNKNOW;
}else{
return LocalTransactionState.ROLLBACK_MESSAGE;
}
}
});
}
public boolean sendMessage(Object value){
Map<String,Object> mapArgs= new HashMap<>();
mapArgs.put("key",value);;
Message message=new Message(topicName,"Tag", "message");
TransactionSendResult transactionSendResult=null;
try {
transactionSendResult = transactionMQProducer.sendMessageInTransaction(message, mapArgs);
} catch (MQClientException e) {
e.printStackTrace();
return false;
}
if(transactionSendResult.getLocalTransactionState() == LocalTransactionState.COMMIT_MESSAGE){
return true;
}else if(transactionSendResult.getLocalTransactionState() == LocalTransactionState.ROLLBACK_MESSAGE){
return false;
}else {
return false;
}
}
}
public class Consumer {
public static void main(String[] args) throws MQClientException {
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("test_consumerGroup");
consumer.setNamesrvAddr(Const.NAMESRV_ADDR);
consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);
consumer.subscribe("test_topic","*");
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
MessageExt msg = list.get(0);
try {
}catch (Exception e){
e.printStackTrace();
int reconsumeTimes = msg.getReconsumeTimes();
if(reconsumeTimes == 2){
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
return ConsumeConcurrentlyStatus.RECONSUME_LATER;
}
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
System.out.println("消费服务启动...");
consumer.start();
}
}
参考