美团面试官:订单自动关闭的功能该如何实现?我:有点懵~

该博客介绍了如何利用Redis的键值对过期时间来实现订单自动关闭功能。在创建订单时,将订单号作为键存入Redis并设置过期时间。当Redis检测到键过期时,通过监听器触发相应操作,例如更新数据库中的订单状态。配置Redis的notify-keyspace-events以启用键过期提醒,并在Spring Boot应用中添加依赖和监听器来处理过期事件。
摘要由CSDN通过智能技术生成

点击卡片关注 ????

来源:https://juejin.cn/post/6919095552835584008



# 业务场景

我们以订单功能为例说明下:生成订单后一段时间不支付订单会自动关闭。最简单的想法是设置定时任务轮询,但是每个订单的创建时间不一样,定时任务的规则无法设定,如果将定时任务执行的间隔设置的过短,太影响效率。还有一种想法,在用户进入订单界面的时候,判断时间执行相关操作。方式可能有很多,在这里介绍一种监听 Redis 键值对过期时间来实现订单自动关闭。


# 实现思路

在生成订单时,向 Redis 中增加一个 KV 键值对,K 为订单号,保证通过 K 能定位到数据库中的某个订单即可,V 可为任意值。假设,生成订单时向 Redis 中存放 K 为订单号,V 也为订单号的键值对,并设置过期时间为 30 分钟,如果该键值对在 30 分钟过期后能够发送给程序一个通知,或者执行一个方法,那么即可解决订单关闭问题。实现:通过监听 Redis 提供的过期队列来实现,监听过期队列后,如果 Redis 中某一个 KV 键值对过期了,那么将向监听者发送消息,监听者可以获取到该键值对的 K,注意,是获取不到 V 的,因为已经过期了,这就是上面所提到的,为什么要保证能通过 K 来定位到订单,而 V 为任意值即可。拿到 K 后,通过 K 定位订单,并判断其状态,如果是未支付,更新为关闭,或者取消状态即可。

# 开启 Redis key 过期提醒

修改 redis 相关事件配置。找到 redis 配置文件 redis.conf,查看 notify-keyspace-events 配置项,如果没有,添加 notify-keyspace-events Ex,如果有值,则追加 Ex,相关参数说明如下:

  • K:keyspace 事件,事件以 keyspace@ 为前缀进行发布

  • E:keyevent 事件,事件以 keyevent@ 为前缀进行发布

  • g:一般性的,非特定类型的命令,比如del,expire,rename等

  • $:字符串特定命令

  • l:列表特定命令

  • s:集合特定命令

  • h:哈希特定命令

  • z:有序集合特定命令

  • x:过期事件,当某个键过期并删除时会产生该事件

  • e:驱逐事件,当某个键因 maxmemore 策略而被删除时,产生该事件

  • A:g$lshzxe的别名,因此”AKE”意味着所有事件


# 引入依赖

在 pom.xml 中添加 org.springframework.boot:spring-boot-starter-data-redis 依赖

<dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-data-redis</artifactId></dependency>

# 相关配置

定义配置 RedisListenerConfig 实现监听 Redis key 过期时间

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;
@Configurationpublic class RedisListenerConfig {
    @Bean    RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();        container.setConnectionFactory(connectionFactory);        return container;    }}

定义监听器 RedisKeyExpirationListener,实现KeyExpirationEventMessageListener 接口,查看源码发现,该接口监听所有 db 的过期事件 keyevent@*:expired"

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;
/** * 监听所有db的过期事件__keyevent@*__:expired" */@Componentpublic class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {
    public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {        super(listenerContainer);    }
    /**     * 针对 redis 数据失效事件,进行数据处理     * @param message     * @param pattern     */    @Override    public void onMessage(Message message, byte[] pattern) {
        // 获取到失效的 key,进行取消订单业务处理        String expiredKey = message.toString();        System.out.println(expiredKey);    }}

推荐阅读:

华为正式宣布养猪,网友沸腾:支持华为自救!

API 面试四连杀:接口如何设计?安全如何保证?签名如何实现?防重如何实现?

Spring Boot 中引入 MyBatisPlus 的常规流程

垃圾代码和优质代码的区别?

入职腾讯第九年,我辞职了

点击卡片关注,查看更多精彩

点分享点点赞点在看
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值