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

 

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