SpringBoot项目中遇到的订单支付超时未支付关闭订单的解决方案(RabbitMQ生产者消费者之间的使用示例)

1、扫表轮循

定时任务 => 获取数据 => 数据层 => 筛选出过期的数据 => 批量关闭超时订单

在这里插入图片描述

优点:实现简单、适用于小项目、数据量比较少
缺点:订单量过大的时候查询和修改数据库压力大、服务器内存消耗大、IO瓶颈

2、Redis懒删除

用户获取订单信息 => 判断是否过期 => 关闭超时订单

在这里插入图片描述

优点:实现简单
缺点:必须要用户查询该条订单信息的时候才会触发

3、RabbitMQ或Kafka延迟消息队列

用户下单 => 发送延迟消息 => 延迟队列存储 => 到期消费 => 检测支付状态 => 未支付? => 关闭超时订单

在这里插入图片描述

缺点:需要引入消息中间件
优点:随时能从队列里面移除实时取消的订单、不会占用应用服务器的资源、异步化处理

SpringBoot + RabbitMQ延迟消息队列实现(死信队列)

死信,顾名思义就是无法被消费的消息。一般来说,producer 将消息投递到 broker 或者直接到queue 里了,consumer 从 queue 取出消息进行消费,但某些时候由于特定的原因导致queu 中的某些消息无法被消费,这样的消息如果没有后续的处理,就变成了死信,有死信自然就有了死信队列。

而由于TTL(生存时间)过期导致的死信,就是我们实现延迟队列的的方式。

也就是说我们的正常的队列中某个值达到了特定的时间,过期了,这时候这个值将会到达死信队列中去,我们只需要监听死信队列就可以操作订单支付超时自动关闭的业务了。

1、pom.xml中引入RabbitMQ

<!-- springboot集成rabbitMQ -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

在这里插入图片描述

2、application.yml中配置RabbitMQ

#rabbitmq配置
spring:
  rabbitmq:
    host: 106.14.34.213
    port: 5672
    username: ckm
    password: ckm
    virtual-host: /

在这里插入图片描述

3、配置RabbitMQConfig交换机和队列

package com.ckm.yangle.rabbitmqjob.config;

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

import java.util.HashMap;
import java.util.Map;

//rabbitMQ绑定交换机 / 队列
@Configuration
public class RabbitMQConfig {

    //========================================================订单未支付定时关闭RabbitMQ Queue========================================================//

    //订单交换机
    @Bean
    public DirectExchange directExchangeOrder(){
        return new DirectExchange("order-direct-exchange");
    }
    //订单队列
    @Bean
    public Queue orderDataChangeQueue() {

        Map<String, Object> args = new HashMap<>(3);
        //声明当前队列绑定到死信交换机
        args.put("x-dead-letter-exchange", "order-dead-direct-exchange");
        //声明当前队列绑定到死信路由 key
        args.put("x-dead-letter-routing-key", "routing-order-dead");
        //声明队列的 TTL 过期时间 设置队列的过期时间为10秒(10000),单位为毫秒
        args.put("x-message-ttl", 10000);
        return QueueBuilder.durable("order-queue").withArguments(args).build();

    }
    //队列绑定交换机
    @Bean
    public Binding orderBindExchange(Queue orderDataChangeQueue, DirectExchange directExchangeOrder) {
        return BindingBuilder.bind(orderDataChangeQueue).to(directExchangeOrder).with("routing-order");
    }


    // 声明 死信队列交换机 order-dead-direct-exchange
    @Bean
    public DirectExchange directExchangeOrderDead() {
        return new DirectExchange("order-dead-direct-exchange");
    }
    //声明死信队列 order-dead-queue
    @Bean
    public Queue orderDeadDataChangeQueue() {
        return new Queue("order-dead-queue",true);
    }
    //声明死信队列绑定死信交换机
    @Bean
    public Binding orderDeadBindExchange(Queue orderDeadDataChangeQueue, DirectExchange directExchangeOrderDead) {
        return BindingBuilder.bind(orderDeadDataChangeQueue).to(directExchangeOrderDead).with("routing-order-dead");
    }
}

在这里插入图片描述

4、监听RabbitMQ死信队列消费者消费

package com.ckm.yangle.rabbitmqjob.order;

import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.Date;

@Slf4j
@Component
public class RabbitMQDataSyncListenerOrder {
    @RabbitListener(queues = "order-dead-queue")
    public void receiveD(Message message, Channel channel) throws IOException {
        String msg = new String(message.getBody());
        log.info("当前时间:{},收到死信队列信息:{}", new Date().toString(), msg);
    }
}

在这里插入图片描述

5、在业务中生产者生产消息

log.info("当前时间:{},发送一条信息给一个 TTL 队列:{}", new Date(), "消息测试");
rabbitTemplate.convertAndSend("order-direct-exchange", "routing-order", "消息来自 ttl 为 30S 的队列: " + "消息测试");

在这里插入图片描述

6、测试结果

业务执行生产消息 => 到达过期时间 => 监听到死信队列

在这里插入图片描述

4、Redis过期监听机制

用户下单 => 发送Redis消息 => Redis Key过期时间 => 过期回调 => 检测支付状态 => 未支付?关闭超时订单

在这里插入图片描述

缺点:订单量过大非常消耗Redis服务器资源
优点:不会占用应用服务器的资源、应用的宕机不会对Redis产生影响、Redis过期时间准确度高

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

令人作呕的溏心蛋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值