通過redis鍵空間通知實現日程的提醒通知
阿新 • • 發佈:2022-04-15
什麼是延遲任務?
顧明思議,我們把需要延遲執行的任務叫做延遲任務。
延遲任務的使用場景有以下這些:
- 紅包 24 小時未被查收,需要延遲執退還業務;
- 每個月賬單日,需要給使用者傳送當月的對賬單;
- 訂單下單之後 30 分鐘後,使用者如果沒有付錢,系統需要自動取消訂單。
- 新增日程事項選擇某個時間後,需要到點或提前多久,或每天,或每週等,傳送當前日程通知。
等事件都需要使用延遲任務。
使用 Redis 實現延遲任務的方法大體可分為兩類:
- 和通過鍵空間通知的方式。
- 通過 zset 資料判斷的方式。
1.通過鍵空間通知
預設情況下 Redis 伺服器端是不開啟鍵空間通知的,需要我們通過 config set notify-keyspace-events Ex
的命令手動開啟,
開啟鍵空間通知後,我們就可以拿到每個鍵值過期的事件,我們利用這個機制實現了給每個人開啟一個定時任務的功能,實現程式碼如下:
import org.springframework.stereotype.Component; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; /* * redis資料連線池的工具類
* 這個有點老 * @author lcl */ @Component publicclass JedisUtils { private static JedisPool pool; static { //讀取配置檔案 String host = "localhost"; //獲取埠號 int port = Integer.parseInt("6379"); //獲取最大連線數 int maxTotal = Integer.parseInt("50"); //獲取閒時連線數 int maxIdle = Integer.parseInt("20");//建立連線池配置物件 JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); jedisPoolConfig.setMaxIdle(maxIdle); jedisPoolConfig.setMaxTotal(maxTotal); //建立連線池物件 pool = new JedisPool(jedisPoolConfig, host, port); } //建立方法 連線池物件 public static Jedis getJedis(){ return pool.getResource(); } //釋放資源 public static void close(Jedis jedis){ if(jedis!=null){ jedis.close(); } } private static void close(JedisPool pool){ if (pool!=null){ pool.close(); } } }
Service
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.stereotype.Component; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPubSub; /** * 通過redis實現 定時任務傳送通知 * @author lcl */ @Component public class RedisTaskServiceImpl implements ApplicationRunner { private static final Logger log = LoggerFactory.getLogger(RedisTaskServiceImpl.class); /** * 鍵空間通知 */ public void doTask() { //連線redis的工具類,你得自己設定一下 Jedis jedis = JedisUtils.getJedis(); // 訂閱過期訊息 jedis.psubscribe(new JedisPubSub() { @Override public void onPMessage(String pattern, String channel, String message) { /** * 我存了兩個key * 一個是過期時間的,一個是不過期的 * 如: * rediskey 會過期 * rediskey_01 不會過期 * 根據接收到過期的key,可以通過 key + _01 你儲存的標識 * 得到副key,然後就可以得到value值進行業務等操作,用完就可以刪除 */ log.info("收到消失的key:" + message); } //__keyevent@0__:expired 為你的 redis 訂閱頻道名稱 預設一般是 0這個資料庫,分庫的後面在想想辦法吧 }, "__keyevent@0__:expired"); } /** * springboot專案啟動時跟著啟動 * @param args * @throws Exception */ @Override public void run(ApplicationArguments args) throws Exception { doTask(); } }
模擬執行測試
啟動專案
redis有資料
等到時間到了後,就會執行
鍵空間通知就是這樣,主要還是這命令總忘記執行,還有另一種方法,就是配置conf檔案,省的每次重啟redis都要執行這程式碼
config set notify-keyspace-events Ex
2.通過 zset 資料
目前還沒用到,後期業務上用到了在補充吧