使用Redis Key失效事件实现定时任务

1、业务场景

  • 在开发中我们可能会遇到下面这样的场景,比如:
  • 当一个用户下单之后后一段时间不支付订单会自动关闭,但每个订单的创建时间又不一样怎么保证30分钟不支付就取消订单呢?
  • 当用户的优惠券或者积分等等快要过期的时候需要提前一天或者几个小时或者30分钟的时候发消息提醒用户,或者去做一些其他的业务处理
  • 那么针对上述场景我们怎么去实现呢?估计很多人首先会想到用定时任务每隔一段时间去执行任务判断吧,这种方式完全可行,但是如果是需要比较精确的提醒呢?就比如我就需要过期前一个小时或者30分钟的时候去提醒,那怎么解决?
  • 如果还用定时任务那么这个跑批的时间间隔我们如何设置,太长或者太短都不太合适,所以针对这种问题,我们强大的redis就可以实现了。

2、Redis key 过期提醒

2.1、在这里介绍一种监听 Redis 键值对过期时间来实现定时任务的功能触发事件机制。

2.2、实现思路

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

3、实现步骤

3.1、修改 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”意味着所有事件

3.2、引入依赖

    • 在 pom.xml 中添加 org.springframework.boot:spring-boot-starter-data-redis 依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

3.3、代码编写

    • 定义配置 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;

@Configuration
public 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"
 */
@Component
public 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);
    }
}

 

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
引用\[1\]:在Spring Boot中使用Redis实现定时任务的步骤如下:首先,在应用程序启动类上加上注解@EnableScheduling,这个注解是用来支持计划任务的。然后,在定时任务执行类中使用@Scheduled注解来指定定时任务的执行间。最后,在启动类上增加注解@EnableScheduling来启用定时任务的功能。\[1\] 引用\[2\]:在定时任务执行类中,可以使用Redis实现定时任务的锁。通过在定时任务执行前获取Redis锁,可以避免多个重复任务同执行的问题。可以使用缓存Redis或者数据库加字段加锁的方式来实现。另外,也可以使用分布式锁工具Zookeeper来实现定时任务的锁。\[2\] 引用\[3\]:具体实现代码如下:首先,引入Redis的依赖。然后,在定时任务执行类中使用@Scheduled注解来指定定时任务的执行间。在任务执行前,通过Redis获取锁,并在任务执行完毕后释放锁。最后,在启动类上增加注解@EnableScheduling来启用定时任务的功能。\[3\] 综上所述,使用Redis实现定时任务的步骤包括:在应用程序启动类上加上@EnableScheduling注解,编写定时任务执行类并使用@Scheduled注解指定执行间,引入Redis依赖,使用Redis获取锁来避免重复执行任务。 #### 引用[.reference_title] - *1* *2* [SpringBoot实践之---集群环境下利用Redis实现定时任务](https://blog.csdn.net/shimilysj/article/details/84889335)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Springboot结合Redis实现分布式定时任务](https://blog.csdn.net/xrq1995/article/details/127521054)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值