SpringBoot實現監聽Redis key失效事件

1.需求

處理訂單過期自動取消,比如下單30分鐘未支付自動更改訂單狀態

2.方案

可以利用redis天然的key自動過期機制,下單時將訂單id寫入redis,過期時間30分鐘,30分鐘後檢查訂單狀態,如果未支付,則進行處理但是key過期了redis有通知嗎?答案是肯定的。

3.試驗步驟

3.1.開啓redis key過期提醒

修改redis相關事件配置。找到redis配置文件redis.conf,查看“notify-keyspace-events”的配置項,如果沒有,添加“notify-keyspace-events Ex”,如果有值,添加Ex,相關參數說明如下:

E:keyevent事件,事件以__keyevent@<db>__爲前綴進行發佈;    
x:過期事件,當某個鍵過期並刪除時會產生該事件; 

3.2.redis測試

打開一個redis-cli ,監控db0的key過期事件

127.0.0.1:6379> PSUBSCRIBE __keyevent@0__:expired
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "__keyevent@0__:expired"
3) (integer) 1

打開另一個redis-cli ,發送定時過期key

127.0.0.1:6379> setex test_key 3 test_value

觀察上一個redis-cli ,會發現收到了過期的keytest_key,但是無法收到過期的value test_value

127.0.0.1:6379> PSUBSCRIBE __keyevent@0__:expired
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "__keyevent@0__:expired"
3) (integer) 1
1) "pmessage"
2) "__keyevent@0__:expired"
3) "__keyevent@0__:expired"
4) "test_key"

4.在springboot中使用

4.1.定義監聽器

定義監聽器,監控__keyevent@0__:expired事件,即db0過期事件。

package com.easygo.listener;

import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;

/**
 * @BelongsProject: easygo
 * @Description: 配置的Redis消息的監聽器,獲取redis的消息並進行處理
 */
public class RedisMessageListener implements MessageListener {

    /**
     * message:要處理的消息
     * @param message 消息內容
     * @param pattern 獲取的頻道信息
     */
    @Override
    public void onMessage(Message message, byte[] pattern) {
        byte[] body = message.getBody();// 建議使用: valueSerializer
        byte[] channel = message.getChannel();
        System.out.print("onMessage >> " );
        System.out.println(String.format("channel: %s, body: %s, bytes: %s"
                ,new String(channel), new String(body), new String(pattern)));
    }
}

4.2.定義配置RedisListenerConfig

/**
 * @BelongsProject: easygo
 * @BelongsPackage: com.easygo.config
 * @Author: bruceliu
 * @QQ:1241488705
 * @CreateTime: 2020-04-08 11:20
 * @Description: SpringBoot整合SpringData Redis
 */
@Configuration
public class RedisConfig {

    @Bean
    RedisMessageListenerContainer container(@Qualifier("jedisConnectionFactory") JedisConnectionFactory factory) {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(factory);
        container.addMessageListener(new RedisMessageListener(), new PatternTopic("__keyevent@0__:expired"));
        return container;
    }
}

4.3.新增key並設置過期時間

/**
     * 新增Redis並設置Redis的key的過期時間
     */
    @Test
    public void testSetValueWithTimeOut() {
        //key的過期時間是10秒種自動失效
        redisTemplate.opsForValue().set("message", "各位老司機,開往紅浪漫的車已經發車...", 30L, TimeUnit.SECONDS);
        System.out.println("設置完成");
    }

4.4.查詢key的過期時間

 public Long testTimeTTL(){
       //根據key獲取過期時間
       Long time1 = redisTemplate.getExpire("baike");
       //根據key獲取過期時間並換算成指定單位
       Long time2 = redisTemplate.getExpire("baike", TimeUnit.SECONDS);
       System.out.println(time2);
       return time2;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章