订单未支付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的过期队列与死信队列,设置消息的存活时间,消息在设置的时间内未被消费,将其投递到死信队列,然后监听死信队列。

 

posted @   xiazihao  阅读(273)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示