RocketMq消息发送方的事务

225 阅读2分钟

简介:

我们都知道目前流行的分布式事务有两大类分别是2pc和TCC。

1.2pc(两阶段提交)

假设a向数据库b写数据,a先尝试提交数据,b会把数据状态变成不可用

当a逻辑成功告诉b确认ok,b会修改数据状态变成可用,否则删除数据。

2.tcc(try confirm cancel)

假设a向数据库b写数据,b会尝试锁住这个数据,当a成功了调confirm方法,当a失败了掉cancel方法,confirm、cancel都由b实现。

rocketmq采用的是两阶段提交思想。

消息发送端开启事务,会先发送halfMessage,broker收到后会把它放入hf队列,然后保存到磁盘,并且给消息发送端一个消息确认。消息发送端收到确认,并且执行完本地所有逻辑后会commit,这样broker里的消息就变成可用的了。当然如果短时间内收不到commit或者rollback的话,broker在此期间会开一个定时任务,去检查hf队列里的消息,看事务是否成功,如果连不上消息发送端的话,默认一段时间后就会把该消息去除。

例子:

public class TransProducer {
    public static void main(String[] args) throws Exception{
        TransactionMQProducer producer = new TransactionMQProducer("xxogp");
        //设置nameserver地址
        producer.setNamesrvAddr("localhost:9876");
        producer.setTransactionListener(new TransactionListener() {
            //执行事务方法
            public LocalTransactionState executeLocalTransaction(Message message, Object o) {
                System.out.println("executeLocalTransaction=====");
                System.out.println(new String(message.getBody()));
                try {
                    int i = 10*10;
                    return LocalTransactionState.COMMIT_MESSAGE;
                } catch (Exception e) {
                    return LocalTransactionState.ROLLBACK_MESSAGE;
                }
            }

            //检查方法
            //Broker端回调,检查事务
            public LocalTransactionState checkLocalTransaction(MessageExt messageExt) {
                System.out.println("checkLocalTransaction=====");
                System.out.println(new String(messageExt.getBody()));
                String flagMessage = "";
                if("事务执行失败".equals(flagMessage)){
                    //将消息变成可用
                    return LocalTransactionState.ROLLBACK_MESSAGE;
                }
                if("事务执行成功".equals(flagMessage)){
                    //直接删除hf message
                    return LocalTransactionState.COMMIT_MESSAGE;
                }
                if("不知道是否成功".equals(flagMessage)){
                    //不知道情况过会再来检查
                    return LocalTransactionState.UNKNOW;
                }
                return LocalTransactionState.COMMIT_MESSAGE;
            }
        });
        producer.start();
        Message message = new Message("mytop111", "你好".getBytes());
        TransactionSendResult send = producer.sendMessageInTransaction(message, null);
        System.out.println("send = " + send);
    }
}