消息队列的方式 解决分布式事务 demo

消息队列的方式 解决分布式事务 demo

rocketMq解决分布式事务

思路

将分布式事务拆分成两个本地事务,对于事务发起方,可理解为生产者,我们只需要保证本地事务和发送消息 这两个动作的一致性,对于事务的另一方可理解为mq 消息的消费者,直需要保证成功消费消息即可。若失败,可重试,可以设定一个重试次数,达到了就人工干预(毕竟这种情况比较小)。

直接上代码:生产者

public class TestTransactionProducer {
    private static Logger logger = LoggerFactory.getLogger(TestTransactionProducer.class);

    public static void main(String[] args) {
        TransactionMQProducer producer = new TransactionMQProducer("transactionProducer");
        producer.setNamesrvAddr(MqConfig.NAME_SERVER);
        //事物监听
        TransactionListener listener = new TransactionListener() {
            @Override
            public LocalTransactionState executeLocalTransaction(Message message, Object o) {
                try {
                    logger.info("开始执行本地事务,也就是自己的业务");
                    logger.info("如果执行成功,就返回本地事务commit");
                    return LocalTransactionState.COMMIT_MESSAGE;
                } catch (Exception e) {
                    logger.error("本地事务执行失败。。。。。。。。。。");
                    return LocalTransactionState.ROLLBACK_MESSAGE;
                }
            }

            @Override
            public LocalTransactionState checkLocalTransaction(MessageExt messageExt) {
                logger.info("自动查本地业务的事务是否成功,一般是手动查询数据库,然后返回 确认或回滚信息");
                return LocalTransactionState.COMMIT_MESSAGE;
            }
        };
        //本地事务执行器
        producer.setTransactionListener(listener);
        try {
            //只需要start 一次
            producer.start();
            //构建消息
            Message msg1 = new Message("TransactionTopic", "tag", "KEY1", "hello RocketMQ 4.7R1111".getBytes());
            Message msg2 = new Message("TransactionTopic", "tag", "KEY2", "hello RocketMQ 4.7R2222".getBytes());
            //发送带有事务性质的消息(发送消息会先执行本地事务,本地成功或失败都会有确认消息返回,)
            TransactionSendResult sendResult1 = producer.sendMessageInTransaction(msg1, null);
            System.out.println(new Date().getTime() + "  msg1发送结果: " + sendResult1);
            TransactionSendResult sendResult2 = producer.sendMessageInTransaction(msg2, null);
            System.out.println(new Date().getTime() + " msg2结果:" + sendResult2);
        } catch (MQClientException e) {
            logger.error(e.getErrorMessage());
        }
    }
}

消费者:

 public static void main(String[] args) throws MQClientException {

        //声明并初始化一个consumer
        //需要一个consumer group名字作为构造方法的参数,这里为consumer1
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("consumer1");

        //同样也要设置NameServer地址
        consumer.setNamesrvAddr("127.0.0.1:9876");

        //这里设置的是一个consumer的消费策略
        //CONSUME_FROM_LAST_OFFSET 默认策略,从该队列最尾开始消费,即跳过历史消息
        //CONSUME_FROM_FIRST_OFFSET 从队列最开始开始消费,即历史消息(还储存在broker的)全部消费一遍
        //CONSUME_FROM_TIMESTAMP 从某个时间点开始消费,和setConsumeTimestamp()配合使用,默认是半个小时以前
        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);

        //设置consumer所订阅的Topic和Tag,*代表全部的Tag
//            consumer.subscribe("TopicTest", "*");
        consumer.subscribe("TransactionTopic", "*");

        //设置一个Listener,主要进行消息的逻辑处理
        consumer.registerMessageListener(new MessageListenerConcurrently() {

            @Override
            public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,
                                                            ConsumeConcurrentlyContext context) {
                //消费之前可以利用redis实现的分布式锁做到不重复消费。
                for (int i = 0; i < msgs.size(); i++) {
                    System.out.println("接收到的消息" + i + ": " + msgs.get(i));
                    System.out.println("消息体 " + i + ":" + new String(msgs.get(i).getBody()));
                }
                //返回消费状态
                //CONSUME_SUCCESS 消费成功
                //RECONSUME_LATER 消费失败,若消费失败,相当于告诉broker 消费失败了,消息你别丢,一会儿我再来消费,自动重试的。
                return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
            }
        });
        //调用start()方法启动consumer
        consumer.start();

        System.out.println("Consumer Started........");
    }

mq用的是4.7 版本的,自己瞎琢磨的,这样应该可以实现分布式事务 数据最终一致性的要求,若有不同的看法,欢迎留言

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值