RocketMQ解决分布式事务问题,简单demo

1.RocketMQ解决分布式事务核心思路:

   1.生产者向我们的Broker(MQ服务器端)发送一条消息设置为半消息,该消息不可以被消费者消费.
   2.在执行我们本地的事务,将本地执行事务结果提交或者回滚告诉Broker
   3.Broker获取本地事务的结果如果为提交的话,将该半消息设置为允许被消费者消费,如果本地事务执行失败的情况下,
      将该半消息直接从Broker中移除.  
   4.如果我们的本地事务没有将结果及时通知给我们的Broker,这时候我们Broker会主动定时(默认60S)查询本地事务结果.
   5.本地事务结果实际上就是一个回调方法,根据自己业务场景封装本地事务结果.

 

项目代码demo: 链接:https://pan.baidu.com/s/11EHZtOw4JFBZ7O1zXMqKuw 
                      提取码:ybtn 
来源:源自蚂蚁课堂学习整理笔记

核心代码

1.向RocketMQ发送半消息 

public String saveOrder() {
        // 提前生成我们的订单id
        String orderId = System.currentTimeMillis() + "";
        /*
         * 1.提前生成我们的半消息
         *
         * 2.半消息发送成功之后,在执行我们的本地事务
         */
        OrderEntity orderEntity = createOrder(orderId);
        String msg = JSONObject.toJSONString(orderEntity);
        MessageBuilder<String> stringMessageBuilder = MessageBuilder.withPayload(msg);
        stringMessageBuilder.setHeader("msg", msg);
        Message message = stringMessageBuilder.build();
        // 该消息不允许被消费者消费
        rocketMQTemplate.sendMessageInTransaction("mayiktProducer",
                "orderTopic", message, null);
        return orderId;

    }

    public OrderEntity createOrder(String orderId) {
        OrderEntity orderEntity = new OrderEntity();
        orderEntity.setName("每特教育第六期平均就业薪资破10万");
        orderEntity.setOrderCreatetime(new Date());
        // 价格是300元
        orderEntity.setOrderMoney(300d);
        // 状态为 未支付
        orderEntity.setOrderState(0);
        Long commodityId = 30L;
        // 商品id
        orderEntity.setCommodityId(commodityId);
        orderEntity.setOrderId(orderId);
        return orderEntity;
    }

2.创建类实现接口RocketMQLocalTransactionListener, 重写本地事务方法和Broker定时检查 .并监听Rocket分组 

@Slf4j
@Component
@RocketMQTransactionListener(txProducerGroup = "mayiktProducer")
public class SyncProducerListener implements RocketMQLocalTransactionListener {
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private TransationalUtils transationalUtils;

    /**
     * 执行我们订单的事务
     */
    @Override
    public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg) {
        MessageHeaders headers = msg.getHeaders();
        Object object = headers.get("msg");
        if (object == null) {
            return RocketMQLocalTransactionState.ROLLBACK;
        }
        String orderMsg = (String) object;
        OrderEntity orderEntity = JSONObject.parseObject(orderMsg, OrderEntity.class);
        TransactionStatus begin = null;
        try {
            begin = transationalUtils.begin();
            int result = orderMapper.addOrder(orderEntity);
            transationalUtils.commit(begin);
            if (result <= 0) {
                return RocketMQLocalTransactionState.ROLLBACK;
            }
            // 告诉我们的Broke可以消费者该消息
            return RocketMQLocalTransactionState.COMMIT;
        } catch (Exception e) {
            if (begin != null) {
                transationalUtils.rollback(begin);
                return RocketMQLocalTransactionState.ROLLBACK;
            }
        }
        return null;
    }

    /**
     * 提供给我们的Broker定时检查
     */
    @Override
    public RocketMQLocalTransactionState checkLocalTransaction(Message msg) {
        MessageHeaders headers = msg.getHeaders();
        Object object = headers.get("msg");
        if (object == null) {
            return RocketMQLocalTransactionState.ROLLBACK;
        }
        String orderMsg = (String) object;
        OrderEntity orderEntity = JSONObject.parseObject(orderMsg, OrderEntity.class);
        String orderId = orderEntity.getOrderId();
        // 直接查询我们的数据库
        OrderEntity orderDbEntity = orderMapper.findOrderId(orderId);
        if (orderDbEntity == null) {
            return RocketMQLocalTransactionState.UNKNOWN;
        }
        return RocketMQLocalTransactionState.COMMIT;
    }
}

3.配置文件

server.port=8088

###连接地址nameServer
rocketmq.name-server=192.168.0.110:9876
rocketmq.producer.group=mayikt_producer

spring.datasource.url=jdbc:mysql://localhost:3306/order?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8

spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章