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
- 初始化一個
項目Spring Boot
-
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>
- 定義配置類
RedisListenerConfig
@Configuration public class RedisListenerConfig { @Bean RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) { RedisMessageListenerContainer container = new RedisMessageListenerContainer(); container.setConnectionFactory(connectionFactory); return container; } }
- 定義資料生産類
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); } } }
- 定義監聽器 實作
KeyExpirationEventMessageListener
接口
檢視源碼發現,該接口監聽所有db的過期事件
定義keyevent@*:expired"
監聽狀态1到期Status1ExpirationListener
定義@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("-----------------------------------"); } } }
監聽狀态2到期Status2ExpirationListener
@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