订单未支付30分钟自动取消是如何实现的?

本文共 2,398 字,预计阅读时间 8 分钟

 


很多时候都能看到,当下了订单后10分钟或30分钟未支付,订单会自动取消,具体是如何实现的呢?

本文使用最常用的几种方式,只说明关键的部分,已30分钟为例。

1.借助redis的过期特性

逻辑:

下单时,订单状态是待支付。将订单编号作为key,下单的时间戳作为value,设置过期时间是30分钟。服务器监听redis的key过期事件,如果是订单过期(还会有其他key过期),则修改订单的状态为已取消。当30分钟后未支付则触发redis过期事件,只需修改订单状态即可。若30分钟内支付成功,则需要删除此订单在redis的值。当然,在支付时,需要检查订单是否已超时或已支付。

关键点:

很明确,只需要在应用中添加监听器监听redis过期即可。

首先是配置redis监听器

复制代码
package com.zxh.example.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;

@Configuration
public class RedisListenerConfig {

    @Bean
    RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);
        return container;
    }

}
复制代码

继承redis键过期监听器,进行业务处理

复制代码
package com.zxh.example.config;

import com.zxh.example.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.stereotype.Component;

@Component
@Slf4j
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {

    @Autowired
    private OrderService orderService;

    public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
        super(listenerContainer);
    }

    @Override
    public void onMessage(Message message, byte[] pattern) {
        // message.toString()可获取失效的key
        String expiredKey = message.toString();
        log.info("------------------redis key 失效; key = {}", expiredKey);
        if (expiredKey.startsWith("order")) {
            // 获取订单orderNo
            String orderNo = expiredKey.substring(expiredKey.lastIndexOf(":") + 1);
            // 将待支付的订单改为已取消(超时未支付)
            orderService.orderPaidTimeout(orderNo);
        }
    }
}
复制代码

注意:由于存在多个键的过期,故必须对键进行判断,是否是订单超时造成的过期。

2.使用RabbitMQ的过期队列

利用RabbitMQ的过期队列与死信队列,设置消息的存活时间,消息在设置的时间内未被消费,将其投递到死信队列,然后监听死信队列。具体请参考RabbitMQ基本入门 这篇文章

 

posted @   钟小嘿  阅读(1371)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
历史上的今天:
2021-07-10 SpringBoot邮件发送
2021-07-10 表单中el-select和el-input的长度不一致?
点击右上角即可分享
微信分享提示