“This is the 14th day of my participation in the First Gwen Challenge 2022.First challenge in 2022”
Review the previous two distributed transactions:
I’ll take you through the mysteries of business
Distributed transaction tool –SEATA
What problems does MQ solve?
To understand the need for MQ, you need to take a look at the emergence and problems of microservices. You need to understand the cause of the problem to understand the role of MQ. For example: payments
In the microservice environment, the three steps will be divided into three services, such as payment service, order service, logistics service. All three, as the name implies, do one thing for themselves.The situation will become complicated. Similarly, taking payment business as an example, the three steps require inter-service invocation, as shown in the figure below. There are two inter-service invocation methods: RESTFUL HTTP and RPC. The difference is not discussed here.
Advantages of microservitization: by dividing the whole into parts and making a single thing for a single service, wireless expansion of a single service can be prevented. No matter from the development, testing, operation and maintenance aspects of a single service is dominant.
Problems caused by microservices:
- Distributed transaction
It is difficult to maintain consistency in calls between services. Take the two calls in the figure above. Because the three steps operate on different databases, JDBC transaction management cannot be used to achieve consistency. And two service calls, because it involves a complex network environment, it is easy to appear, service call failure. Therefore, a very serious problem after microservitization is how to solve the distributed transaction problem.
Resolving distributed transactions
As one of the solutions to distributed transactions, MQ solves the problem of distributed transactions, as shown in the figure below. After completing the payment steps, the payment service sends a paid message to MQ, and the order service changes the status of the order after receiving the message.
MQ of actual combat
- Initialize the MQ queue
@configuration public class MyRabbitMQConfig {/* Queues, exchanges, and bindings in the container will be created automatically if (RabbitMQ) does not exist */ /** * dead letter queues ** @return */ @bean public Queue orderDelayQueue() {/* Queue(String Name, Queue name) Boolean durable, Durable Boolean EXCLUSIVE, Boolean autoDelete, automatically delete Map<String, Object> arguments) attribute */ HashMap<String, Object> arguments = new HashMap<>(); arguments.put("x-dead-letter-exchange", "order-event-exchange"); arguments.put("x-dead-letter-routing-key", "order.release.order"); arguments.put("x-message-ttl", 60000); Queue Queue = new Queue("order.delay. Queue ", true, false, false, arguments); return queue; } /** * storage Queue ** @return */ @bean public Queue orderToStorageQueue() {Queue Queue = new Queue("order.release.storage.queue", true, false, false); return queue; } /** * TopicExchange * * @return */ @Bean public Exchange orderEventExchange() { /* * String name, * boolean durable, * boolean autoDelete, * Map<String, Object> arguments * */ return new TopicExchange("order-event-exchange", true, false); } @Bean public Binding orderCreateBinding() { /* * String destination, Destination (Queue name or switch name) * DestinationType DestinationType (Queue, Exhcange) * String exchange, * String routingKey, * Map<String, Object> arguments * */ return new Binding("order.delay.queue", Binding.DestinationType.QUEUE, "order-event-exchange", "order.create.order", null); } @Bean public Binding orderReleaseStorageBinding() { return new Binding("order.release.storage.queue", Binding.DestinationType.QUEUE, "order-event-exchange", "order.release.order", null); }}Copy the code
- Write an order interface to create an order and lock the inventory by sending a message to the mq wait queue
@override @transactional (rollbackFor = exception.class) public void create(Orders) {log.info("-------> Transactional "); // The local method order.setStatus(orderStatus.noPayment); super.save(order); Decrease (order.getproductid (),order.getCount())); Log.info (" order number: "+ order.getid ()); The info (" -- -- -- -- -- - > send mq "); rabbitTemplate.convertAndSend("order-event-exchange", "order.create.order", order); }Copy the code
- StorageReleaseListener listens to the wait queue (set the wait time according to the actual situation) to determine whether the queue is paid. If not, the order is closed and the inventory is rolled back
@Slf4j @Service public class StorageReleaseListener { @Autowired private orderApi orderApi; @Autowired private IStorageService storageService; @RabbitListener(queues = "order.release.storage.queue") public void handleStockLockedRelease(Orders to, Channel Channel, Message Message) throws IOException {the info (" * * * * * * order. Release. The queue - "roll back the inventory information received * * * * * *"); try { Orders orders = orderApi.GetByOrders(to.getId().longValue()); if("0".equals(orders.getStatus())){ storageService.rollbackStorage(orders.getProductId(),orders.getCount()); } channel.basicAck(message.getMessageProperties().getDeliveryTag(),false); } catch (Exception e) { e.printStackTrace(); }}}Copy the code