トランザクションメッセージの紹介
- RocketMQトランザクションメッセージ(トランザクションメッセージ)ローカルトランザクションのアプリケーションであり、成功または失敗のいずれかを同時にしながら、オペレータにメッセージを送信することは、グローバルトランザクションに定義されてもよいです。RocketMQトランザクションメッセージは、X / Open XA、最終取引メッセージに似た分散トランザクション機能は、分散トランザクションの全会一致採択に到達することができます。
プロセス
- ステージ(送信メッセージを、ローカル・トランザクション・ステータス・メッセージより多くの行を実行します)
- メッセージを送信する(半分メッセージ)
- サーバーの応答メッセージの書き込み結果
- ローカルトランザクション送信結果に従って実行(書き込みが失敗した場合、その後、半分目に見えないメッセージサービス、ローカルロジックが実行されません)
- ロールバックまたはローカル状態に基づいて、トランザクションをコミットし(オペレーションがメッセージ指数、消費者に目に見えるメッセージをコミット生成)
- ステージ2(補償)
- トランザクションメッセージは、サーバから「バックチェック」を起動し、/ロールバック(メッセージ保留状態)にコミットされていません
- プロデューサー対応するローカル業務をチェックするために戻ってステータスメッセージを確認し、確認するために戻ってメッセージを受け取ります
- ローカルトランザクション状態、再コミットまたはロールバック
ケースを解決するための補償ステージは、メッセージのタイムアウトまたは失敗をコミットまたはロールバック前記起こります。
- 詳細なプロセスは、参考文献に行くことができます
トランザクションメッセージを使用します
@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");
//设置nameSrv
transactionMQProducer.setNamesrvAddr(nameAddr);
//开启事务型生产者
transactionMQProducer.start();
//监听本地事务(关键),可以自定义一个类实现 TransactionListener 接口,或是通过匿名内部类
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) {
//当LocalTransaction无法更新prepared消息,会通过这个方法执行本地策略
if(判断1){
//说明本地事务执行成功,提交
return LocalTransactionState.COMMIT_MESSAGE;
}else if(判断2){
//无法判断原因,当消息为UNKNOW时,会定时回查
return LocalTransactionState.UNKNOW;
}else{
//其他则一律回滚
return LocalTransactionState.ROLLBACK_MESSAGE;
}
}
});
}
/*
发送消息
*/
public boolean sendMessage(Integer userId,Integer itemId,Integer amount,Integer promoId,String stockLogId){
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");
//设置NamesrvAddr 及消费位置ConsumeFromWhere
consumer.setNamesrvAddr(Const.NAMESRV_ADDR);
consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);
//订阅topic, * 指该主题下的所有消息都能消费
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();
}
}
参照