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 刷题笔记

    Python 刷题笔记 本文记录了我在使用python刷题的时候遇到的知识点. 目录 Python 刷题笔记 选择.填空题 基本输入输出 sys.stdin 与input 运行脚本时传入参数 Pyth ...

  2. H3C路由器配置示列一

    说明: 如上图所示,192.168.0.0网段是总公司的网络,192.168.3.0和192.168.4.0网段是当前自己分公司的网络,且192.168.3.0是内网不能访问互联网,192.168.4 ...

  3. 本地H5模式写的APP体验可以比APP还好

    很多APP使用H5编写,但APP链接的是远程的url的模式,导致了APP的用户体验极差,因为当你使用远程的H5 url的时候,打开H5页面的速度由网络决定,而不是由手机性能决定,假如用户在没有网络的地 ...

  4. Linux下登录Oracle命令行时删除键^H解决方法

    Linux下登录Oracle命令行时删除键^H解决方法 在linux服务器下登录oracle的控制台,如果输入错误,想用删除键删除时却不能删除,输出的是^H的字符. 方法 用如下的命令可以使删除键生效 ...

  5. vue-element-admin项目核心总结

    1.搭建项目 按照官方文档把整个项目下载下来,安装依赖包npm install, 然后npm run dev 启动项目. 2.项目自定义优化 删除不要的文件,启动项目登录后,发现里面有很多页面,对我们 ...

  6. 拖拽一个元素如此简单,mouse、drag、touch三兄弟的用处

    最近需要做一个投票活动,上传图片时需要拖拽.缩放来裁剪图片,vue的组件不少,不过自己动手才能丰衣足食,一味使用别人的组件实在难以进步,所以自己研究一番. 一.mouse.drag.touch傻傻分不 ...

  7. offset()与position()的区别

    jQuery中有两个获取元素位置的方法offset()和position(),两者的定义如下: offset(): 获取匹配元素在当前视口的相对偏移. 返回的对象包含两个整形属性:top 和 left ...

  8. 智能佳机械软手智能研究版 QB SOFTHAND Research

    ​   智能佳机械软手智能研究版是一种基于软机器人技术的拟人机器人手,灵活.适应性强,能够与周围环境.物体和人类进行交互,同时限制伤害操作员.破坏要处理的产品和破坏机器人本身的风险. 智能佳机械软手智 ...

  9. el-input限制只能输入数字(开发小记)

    输入框中限制通常有三种处理方法 第一种:设置type属性(不推荐) 设置type属性为number,text等等,此方法输入框的后面会有不必要样式出现 <el-input type=" ...

  10. Refit集成consul在asp.net core中的实践

    前言 github:https://github.com/alphayu/ Refit.WebApiClient.Feign等都是支持声名式的Restful服务调用的开源组件. 这个几个组件都综合研究 ...