亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

springboot整合rabbitmq實(shí)現(xiàn)訂單超時(shí)取消案例分析

 更新時(shí)間:2025年01月26日 10:29:52   作者:百萬(wàn)彩票中獎(jiǎng)候選人  
本文介紹了如何使用SpringBoot和RabbitMQ實(shí)現(xiàn)訂單超時(shí)取消功能,通過(guò)配置TTL隊(duì)列和死信交換機(jī),可以管理訂單的超時(shí)邏輯,實(shí)際應(yīng)用中,可以通過(guò)數(shù)據(jù)庫(kù)標(biāo)記訂單狀態(tài)或手動(dòng)確認(rèn)機(jī)制來(lái)防止訂單被錯(cuò)誤取消

訂單超時(shí)取消案例,詳細(xì)請(qǐng)往下看~~~

1. RabbitMQ 配置類

RabbitMQConfig.java

這個(gè)類負(fù)責(zé)定義RabbitMQ的交換機(jī)、隊(duì)列和綁定配置。

import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RabbitMQConfig {

    public static final String ORDER_EXCHANGE = "order-exchange";
    public static final String ORDER_QUEUE = "order-queue";
    public static final String ORDER_ROUTING_KEY = "order-routing-key";

    public static final String TTL_ORDER_QUEUE = "ttl-order-queue";
    public static final String TTL_ORDER_ROUTING_KEY = "ttl-order-routing-key";

    // 定義一個(gè)Direct類型的交換機(jī)
    @Bean
    public DirectExchange orderExchange() {
        return new DirectExchange(ORDER_EXCHANGE);
    }

    // 定義一個(gè)普通的隊(duì)列,用于接收實(shí)際訂單處理的消息
    @Bean
    public Queue orderQueue() {
        return QueueBuilder.durable(ORDER_QUEUE).build();
    }

    // 定義一個(gè)TTL(時(shí)間到期)隊(duì)列,消息會(huì)在這個(gè)隊(duì)列中等待TTL后轉(zhuǎn)發(fā)到實(shí)際處理隊(duì)列
    @Bean
    public Queue ttlOrderQueue() {
        return QueueBuilder.durable(TTL_ORDER_QUEUE)
                           .withArgument("x-dead-letter-exchange", ORDER_EXCHANGE) // 設(shè)置死信交換機(jī)
                           .withArgument("x-dead-letter-routing-key", ORDER_ROUTING_KEY) // 設(shè)置死信路由鍵
                           .withArgument("x-message-ttl", 60000) // 設(shè)置TTL為60秒
                           .build();
    }

    // 將實(shí)際處理隊(duì)列綁定到交換機(jī)
    @Bean
    public Binding orderBinding() {
        return BindingBuilder.bind(orderQueue()).to(orderExchange()).with(ORDER_ROUTING_KEY);
    }

    // 將TTL隊(duì)列綁定到交換機(jī)
    @Bean
    public Binding ttlOrderBinding() {
        return BindingBuilder.bind(ttlOrderQueue()).to(orderExchange()).with(TTL_ORDER_ROUTING_KEY);
    }
}

詳細(xì)解釋:

交換機(jī)(Exchange)

  • orderExchange:定義了一個(gè)DirectExchange類型的交換機(jī)order-exchange
  • Direct類型的交換機(jī)會(huì)根據(jù)路由鍵(routing key)精確匹配消息隊(duì)列。

隊(duì)列(Queue)

  • orderQueue:定義了一個(gè)普通的隊(duì)列order-queue,這個(gè)隊(duì)列用于接收和處理訂單消息。
  • ttlOrderQueue:定義了一個(gè)TTL隊(duì)列ttl-order-queue,這個(gè)隊(duì)列設(shè)置了TTL(x-message-ttl)為60秒。當(dāng)消息在這個(gè)隊(duì)列中超過(guò)60秒未被消費(fèi),它會(huì)變成死信消息(Dead Letter),然后根據(jù)配置的死信交換機(jī)(x-dead-letter-exchange)和死信路由鍵(x-dead-letter-routing-key)轉(zhuǎn)發(fā)到指定的隊(duì)列。

綁定(Binding)

  • orderBinding:將order-queue隊(duì)列綁定到order-exchange交換機(jī),使用路由鍵order-routing-key
  • ttlOrderBinding:將ttl-order-queue隊(duì)列綁定到order-exchange交換機(jī),使用路由鍵ttl-order-routing-key。這意味著發(fā)送到這個(gè)路由鍵的消息會(huì)首先進(jìn)入TTL隊(duì)列。

2. 訂單服務(wù)

OrderService.java

這個(gè)類負(fù)責(zé)訂單的創(chuàng)建和付款邏輯。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.UUID;

@Service
public class OrderService {

    private static final Logger logger = LoggerFactory.getLogger(OrderService.class);

    @Autowired
    private AmqpTemplate amqpTemplate;

    // 創(chuàng)建訂單并發(fā)送消息到TTL隊(duì)列
    public void createOrder(String orderId) {
        logger.info("創(chuàng)建訂單: {}", orderId);
        amqpTemplate.convertAndSend(RabbitMQConfig.ORDER_EXCHANGE, RabbitMQConfig.TTL_ORDER_ROUTING_KEY, orderId);
    }

    // 支付訂單
    public void payOrder(String orderId) {
        logger.info("支付訂單: {}", orderId);
        // 訂單支付邏輯
        // 支付成功后,需要取消TTL隊(duì)列中的消息,防止訂單被取消
        // 可以通過(guò)業(yè)務(wù)邏輯來(lái)實(shí)現(xiàn),比如數(shù)據(jù)庫(kù)狀態(tài)變化
    }
}

詳細(xì)解釋:

  • createOrder方法:當(dāng)創(chuàng)建一個(gè)訂單時(shí),會(huì)生成一個(gè)唯一的訂單ID,并將其發(fā)送到order-exchange交換機(jī),使用ttl-order-routing-key路由鍵。這會(huì)將消息放入TTL隊(duì)列ttl-order-queue。
  • payOrder方法:模擬支付訂單的過(guò)程。支付成功后,需要在業(yè)務(wù)邏輯中處理,確保訂單不會(huì)被超時(shí)取消。這個(gè)例子沒(méi)有實(shí)現(xiàn)具體的取消邏輯,但在實(shí)際應(yīng)用中,可以通過(guò)數(shù)據(jù)庫(kù)或其他機(jī)制來(lái)實(shí)現(xiàn)。

3. 超時(shí)監(jiān)聽(tīng)器

OrderTimeoutListener.java

這個(gè)類負(fù)責(zé)監(jiān)聽(tīng)超時(shí)消息并取消訂單。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
public class OrderTimeoutListener {

    private static final Logger logger = LoggerFactory.getLogger(OrderTimeoutListener.class);

    // 監(jiān)聽(tīng)來(lái)自order-queue隊(duì)列的消息
    @RabbitListener(queues = RabbitMQConfig.ORDER_QUEUE)
    public void handleOrderTimeout(String orderId) {
        logger.info("訂單超時(shí)未支付,取消訂單: {}", orderId);
        // 取消訂單的業(yè)務(wù)邏輯
    }
}

詳細(xì)解釋:

  • handleOrderTimeout方法:監(jiān)聽(tīng)order-queue隊(duì)列中的消息。
  • 當(dāng)TTL時(shí)間到期后,消息會(huì)被轉(zhuǎn)發(fā)到這個(gè)隊(duì)列,然后這個(gè)方法會(huì)被觸發(fā),處理訂單超時(shí)取消的業(yè)務(wù)邏輯。

4. 主應(yīng)用程序

RabbitMqOrderApplication.java

這個(gè)類是Spring Boot的主應(yīng)用程序類,包含了啟動(dòng)邏輯和示例訂單處理流程。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class RabbitMqOrderApplication implements CommandLineRunner {

    @Autowired
    private OrderService orderService;

    public static void main(String[] args) {
        SpringApplication.run(RabbitMqOrderApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        String orderId = UUID.randomUUID().toString();
        orderService.createOrder(orderId);
        
        // 模擬延遲支付
        Thread.sleep(30000); // 30秒后支付
        orderService.payOrder(orderId);
    }
}

詳細(xì)解釋:

  • CommandLineRunner接口:實(shí)現(xiàn)了這個(gè)接口的run方法會(huì)在Spring Boot應(yīng)用啟動(dòng)后立即執(zhí)行。
  • run方法:生成一個(gè)唯一的訂單ID,調(diào)用orderService.createOrder方法創(chuàng)建訂單,并將訂單消息發(fā)送到TTL隊(duì)列。然后,模擬延遲30秒后調(diào)用orderService.payOrder方法支付訂單。

總結(jié)

在這個(gè)示例中,我們展示了如何使用Spring Boot和RabbitMQ實(shí)現(xiàn)一個(gè)簡(jiǎn)單的訂單超時(shí)取消功能。通過(guò)配置TTL隊(duì)列和死信交換機(jī),可以有效地管理訂單的超時(shí)邏輯。

實(shí)際應(yīng)用中,可以根據(jù)具體需求調(diào)整TTL時(shí)間和業(yè)務(wù)邏輯處理訂單狀態(tài)。

在支付成功后需要取消TTL隊(duì)列中的消息,防止訂單被取消,可以通過(guò)以下幾種方法來(lái)實(shí)現(xiàn):

方法一:使用數(shù)據(jù)庫(kù)標(biāo)記和業(yè)務(wù)邏輯過(guò)濾

1.數(shù)據(jù)庫(kù)標(biāo)記訂單狀態(tài)

  • 在訂單數(shù)據(jù)庫(kù)中添加一個(gè)字段來(lái)標(biāo)記訂單狀態(tài),例如status字段,狀態(tài)值可以是NEW、PAID、CANCELLED等。
  • 當(dāng)訂單支付成功后,將訂單狀態(tài)更新為PAID。

2.業(yè)務(wù)邏輯過(guò)濾

  • 在處理超時(shí)消息時(shí),首先檢查訂單的狀態(tài),如果訂單已經(jīng)支付(狀態(tài)為PAID),則忽略取消操作。

方法二:使用消息確認(rèn)機(jī)制(ACK/NACK)

手動(dòng)ACK消息

  • 配置RabbitMQ的消息監(jiān)聽(tīng)器,使其使用手動(dòng)確認(rèn)(ACK)模式。
  • 當(dāng)訂單支付成功時(shí),通過(guò)業(yè)務(wù)邏輯顯式地確認(rèn)消息,這樣RabbitMQ就不會(huì)將消息重新發(fā)送。

具體實(shí)現(xiàn)示例

下面我們?cè)敿?xì)介紹如何實(shí)現(xiàn)這兩種方法。

方法一:使用數(shù)據(jù)庫(kù)標(biāo)記和業(yè)務(wù)邏輯過(guò)濾

1. 修改訂單服務(wù)

  • OrderService.java
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class OrderService {

    private static final Logger logger = LoggerFactory.getLogger(OrderService.class);

    @Autowired
    private AmqpTemplate amqpTemplate;

    @Autowired
    private OrderRepository orderRepository;

    // 創(chuàng)建訂單并發(fā)送消息到TTL隊(duì)列
    public void createOrder(String orderId) {
        Order order = new Order(orderId, "NEW");
        orderRepository.save(order);

        logger.info("創(chuàng)建訂單: {}", orderId);
        amqpTemplate.convertAndSend(RabbitMQConfig.ORDER_EXCHANGE, RabbitMQConfig.TTL_ORDER_ROUTING_KEY, orderId);
    }

    // 支付訂單
    public void payOrder(String orderId) {
        Order order = orderRepository.findById(orderId).orElse(null);
        if (order != null && "NEW".equals(order.getStatus())) {
            order.setStatus("PAID");
            orderRepository.save(order);

            logger.info("支付訂單: {}", orderId);
        }
    }
}

2. 修改訂單超時(shí)監(jiān)聽(tīng)器

  • OrderTimeoutListener.java
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class OrderTimeoutListener {

    private static final Logger logger = LoggerFactory.getLogger(OrderTimeoutListener.class);

    @Autowired
    private OrderRepository orderRepository;

    // 監(jiān)聽(tīng)來(lái)自order-queue隊(duì)列的消息
    @RabbitListener(queues = RabbitMQConfig.ORDER_QUEUE)
    public void handleOrderTimeout(String orderId) {
        Order order = orderRepository.findById(orderId).orElse(null);
        if (order != null && "NEW".equals(order.getStatus())) {
            order.setStatus("CANCELLED");
            orderRepository.save(order);

            logger.info("訂單超時(shí)未支付,取消訂單: {}", orderId);
        } else {
            logger.info("訂單已經(jīng)處理: {}", orderId);
        }
    }
}

3. 訂單實(shí)體和倉(cāng)庫(kù)

  • Order.java
import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class Order {

    @Id
    private String id;
    private String status;

    // getters and setters
    public Order() {
    }

    public Order(String id, String status) {
        this.id = id;
        this.status = status;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }
}
  • OrderRepository.java
import org.springframework.data.repository.CrudRepository;

public interface OrderRepository extends CrudRepository<Order, String> {
}

方法二:使用消息確認(rèn)機(jī)制(ACK/NACK)

1. 配置消息監(jiān)聽(tīng)器為手動(dòng)確認(rèn)模式

  • RabbitMQConfig.java
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RabbitMQConfig {

    // 其他配置...

    @Bean
    public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(ConnectionFactory connectionFactory) {
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        factory.setConnectionFactory(connectionFactory);
        factory.setAcknowledgeMode(AcknowledgeMode.MANUAL); // 設(shè)置手動(dòng)確認(rèn)
        return factory;
    }
}

2. 修改訂單超時(shí)監(jiān)聽(tīng)器以手動(dòng)確認(rèn)消息

  • OrderTimeoutListener.java
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.ChannelAwareMessageListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.rabbitmq.client.Channel;

@Component
public class OrderTimeoutListener implements ChannelAwareMessageListener {

    private static final Logger logger = LoggerFactory.getLogger(OrderTimeoutListener.class);

    @Autowired
    private OrderRepository orderRepository;

    @Override
    @RabbitListener(queues = RabbitMQConfig.ORDER_QUEUE)
    public void onMessage(Message message, Channel channel) throws Exception {
        String orderId = new String(message.getBody());
        Order order = orderRepository.findById(orderId).orElse(null);
        if (order != null && "NEW".equals(order.getStatus())) {
            order.setStatus("CANCELLED");
            orderRepository.save(order);
            logger.info("訂單超時(shí)未支付,取消訂單: {}", orderId);
        } else {
            logger.info("訂單已經(jīng)處理: {}", orderId);
        }

        // 手動(dòng)確認(rèn)消息
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    }
}

通過(guò)這種方式,我們可以在訂單支付成功后,通過(guò)數(shù)據(jù)庫(kù)標(biāo)記或手動(dòng)確認(rèn)機(jī)制,確保消息不會(huì)被重新發(fā)送或處理,從而防止訂單被錯(cuò)誤地取消。

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

最新評(píng)論