RocketMq transaction message personal understanding and integration springboot

Table of contents

Before learning, let's understand what is rocketMq's transaction message?

Why is there an ack mechanism, and a transaction message is also proposed. What can rocketmq transaction messages bring me?

Springboot integrates RocketMq to send transaction messages 



Before learning, let's understand what is rocketMq's transaction message?

        Adhering to the lazy character. Check out blogs written by others here!  rocketmq transaction message

 Rough Process Summary

1) The sender sends a "Prepare" message to RocketMQ.

2) RocketMQ will reply to the sender that the message has been sent successfully after receiving the "to be confirmed" (generally written to a HalfTopic topic <RMQ_SYS_TRANS_HALF_TOPIC>) successfully.

When the first phase of message sending is completed.

The sender starts executing local event logic.

3) The sender sends a second confirmation (Commit or Rollback) message to RocketMQ according to the event execution result. RocketMQ marks the first-stage message as deliverable after receiving the Commit (these

The actual topic (RealTopic) will be sent when the message enters production, and the subscriber will be able to receive the message; the message in the first stage will be deleted when the Rollback state is received, and the subscriber will not receive the message.

4) If there is an abnormal situation, the second confirmation submitted in step 3 does not reach RocketMQ in the end, and the server will initiate a checkback request for the "pending confirmation" message after a fixed period of time.

5) After the sender receives the message checkback request (if the Producer that sent the first-stage message cannot work, the checkback request will be sent to other Producers in the same Group as the Producer),

Return the Commit Roolback status by checking the local event execution result of the corresponding message.

Why is there an ack mechanism, and a transaction message is also proposed. What can rocketmq transaction messages bring me?

Comparison of three sending methods of rocketMq

      

         Three sending methods, except one-way sending, no sending error feedback. The other two can know whether the message is sent to the server.

        certainly. The first two types also return failure to send messages. The actual message has been sent to mq. At this time, consumers need to ensure idempotence themselves. Not considered here.

Then there is a message confirmation mechanism. Why is there still news about things. In what scenarios can transaction messages be used?

After thinking about it, I simulated a scene myself. The business is probably to push the message to deduct the inventory after the consumption is successful. If you simply use the message confirmation mechanism. There may be a situation.

1. Successful consumption. Send queue succeeded. It's okay, it's probably the case

2. Consumption failed. If you roll back directly, the message will not be pushed.

3. The consumption is successful, but the sending queue returns a failure. Forehead. How to deal with this.

Roll back consumer business? Everyone paid successfully because the sending queue failed. You spit out the meat you eat. This is obviously impossible.

not deal with? No processing, no inventory deduction, no bonus points. You answer your leader like this to see if your leader beats you.

Send an exception, insert the send failure table? This seems possible. And it seems that many people do the same. Is there a problem with doing so? Most likely no problem. However, it is also possible that the insert failure table fails to insert. But it is a small probability.

The scene of things news here is reflected. thing news. It can also be understood as reliable news. Or a solution. At least that's how I understand it here

So let's keep the code in one word!

Springboot integrates RocketMq to send transaction messages 

Pom is introduced here. If there is a boot-starter here, you can directly use the native client. If you want to see the implementation first, directly search for the entry class below.


		<dependency>
			<groupId>org.apache.rocketmq</groupId>
			<artifactId>rocketmq-spring-boot-starter</artifactId>
			<version>2.1.1</version>
		</dependency>

 

 Closer to home

Simulate the business, the order transaction is successful, the order table order_info inserts data, and the order_slip flow table inserts records. And push the message queue.

public interface IOrderInfoService extends IService<OrderInfo> {

    /**
     * 交易成功 插入流水
     * @param orderInfo
     */
    void insertOrderInfo(OrderInfo orderInfo);

}
public interface IOrderSlipService extends IService<OrderSlip> {
    /**
     * 是否交易成功
     * @param orderId
     * @return
     */
    boolean isExistTx(String orderId);

}
@Service
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements IOrderInfoService {

    @Resource
    private IOrderSlipService orderSlipService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insertOrderInfo(OrderInfo orderInfo) {

        baseMapper.insert(orderInfo);
        OrderSlip orderSlip = new OrderSlip();
        orderSlip.setOrderId(orderInfo.getOrderId());
        orderSlip.setStatus(1);
        orderSlipService.save(orderSlip);

    }
}
@Service
public class OrderSlipServiceImpl extends ServiceImpl<OrderSlipMapper, OrderSlip> implements IOrderSlipService {

    @Override
    public boolean isExistTx(String orderId) {
        QueryWrapper<OrderSlip> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("order_id",orderId);
        queryWrapper.eq("status",1);
        OrderSlip orderSlip = baseMapper.selectOne(queryWrapper);
        return (orderSlip!=null);
    }
}

rocketMqTransactionListener implementation

@Component
@RocketMQTransactionListener
public class RocketMqTransactionListenerImpl implements RocketMQLocalTransactionListener{


    @Resource
    private IOrderInfoService orderInfoService;

    @Resource
    private IOrderSlipService orderSlipService;



    @Override
    public RocketMQLocalTransactionState executeLocalTransaction(Message message, Object arg) {
        try{
            // 执行业务逻辑 控制本地事务
            String jsonString = new String((byte[]) message.getPayload());
            // 比如 订单交易-插入流水 (同一事务)
            OrderInfo orderInfo = JSON.parseObject(jsonString, OrderInfo.class);
            orderInfoService.insertOrderInfo(orderInfo);
            return RocketMQLocalTransactionState.COMMIT;
        }catch (Exception e){
            System.out.println(e);
            return RocketMQLocalTransactionState.ROLLBACK;
        }

    }

    @Override
    public RocketMQLocalTransactionState checkLocalTransaction(Message msg) {
        RocketMQLocalTransactionState state;
        String jsonString = new String((byte[]) msg.getPayload());
        OrderInfo orderInfo = JSON.parseObject(jsonString, OrderInfo.class);
        boolean existTx = orderSlipService.isExistTx(orderInfo.getOrderId());

        if(existTx){
            state =  RocketMQLocalTransactionState.COMMIT;
        }else{
            state = RocketMQLocalTransactionState.UNKNOWN;
        }
        return state;
    }
}

Controller implementation

@RestController
@RequestMapping("/mq/product")
public class RocketMqProductController {

    @Resource
    private RocketMQTemplate rocketMQTemplate;

    @RequestMapping("/test")
    public void myTestTran(){
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setGoodId(11);
        orderInfo.setNum(2);
        String orderId = UUID.randomUUID().toString().replaceAll("-","");
        orderInfo.setOrderId(orderId);
        Message<String> message = MessageBuilder.withPayload(JSON.toJSONString(orderInfo)).build();
        TransactionSendResult tx_product_msg = rocketMQTemplate.sendMessageInTransaction("tx_product_msg", message, null);
        System.out.println("发送成功");
    }

}

Here is a demo. and possible realizations. Of course, it is impossible to be so simple in production and need to be considered in accordance with the business. rocketMq just provides a template.

To put it simply, if the business is successful. The rocket commit failed. There will be scheduled tasks to call the pipeline interface to check whether the order is successful. Of course, in reality, it is impossible to just judge whether there is such a record.

This is just my opinion. If there is an error, please point it out. Thanks again

Guess you like

Origin blog.csdn.net/evil_lrn/article/details/121553811