在使用緩存的時候,咱們時不時會遇到這樣一個需求,根據緩存鍵的規則去批量刪除這些數據,比較常見的就是按前綴去刪除。git
舉個簡單的例子,Redis中如今有幾百個商品的數據,這些數據的key值是有必定規律的,都是以product:id
的形式存在的。github
如今因爲不得覺得的緣由要刪除這幾百個商品的數據,這個時候咱們確定就要把緩存鍵以product:
開頭的給所有刪除掉。redis
其實這個需求在Redis中是能夠很容易去實現的。緩存
來看看幾種常見的作法。lua
對於Keys命令,網上有很多血的教訓,對於生產環境仍是要謹慎謹慎再謹慎!能不用就別用。code
Scan命令的話是大部分人推薦的作法,是增量式迭代的一個命令。server
存到SET中就相對繁瑣一點,並且額外佔用了一部份內存。並且在進行刪除的時候還要從這裏讀取出相應的key,同時也要移除這部分key的數據。blog
下面來看看如何在.NET Core中來處理,主要仍是針對SCAN的作法。接口
示例操做Redis用的是StackExchange.Redis。內存
可能有人會有疑惑,不是說Keys命令儘可能不要用嗎?怎麼你還用?
這個還真的要解釋一下!
可能從方法上,咱們找遍全部IServer和IDataBase接口都找不到純粹的SCAN命令(SetScan,HashScan等除外)。
可是若是看過裏面的實現,你就會知道是爲何了!
傳送門:Keys
能夠看看下圖高亮的兩行代碼:
大體意思就是,若是你用的Redis的版本支持SCAN命令,走的就是SCAN,反之只能是KEYS了。
下面定義一個查找RedisKey的方法。
private static RedisKey[] SearchRedisKeys(IServer server, string pattern) { var keys = server.Keys(pattern: pattern).ToArray(); Console.WriteLine("Search Count-{0}",keys.Length); return keys; }
知道那些Key要刪除,剩下的就比較簡單了!
private static void KeysOrScanSolution(IServer server,IDatabase db, string pattern) { db.KeyDelete(SearchRedisKeys(server, pattern)); }
IServer.Keys能夠說是隱式的調用了SCAN命令,那麼咱們天然也能夠顯式的去調用這個命令來完成這些。
private static RedisKey[] SearchRedisKeys(IDatabase db,string pattern) { var keys = new HashSet<RedisKey>(); int nextCursor = 0; do { RedisResult redisResult = db.Execute("SCAN", nextCursor.ToString(), "MATCH", pattern, "COUNT", "1000"); var innerResult = (RedisResult[])redisResult; nextCursor = int.Parse((string)innerResult[0]); List<RedisKey> resultLines = ((RedisKey[])innerResult[1]).ToList(); keys.UnionWith(resultLines); } while (nextCursor != 0); return keys.ToArray(); }
刪除的代碼。
private static void ExecuteSolution(IDatabase db, string pattern) { db.KeyDelete(SearchRedisKeys(db, pattern)); }
固然還有一種作法是調用lua腳本去完成,這裏就不細說了。
雖然上面幾種作法能比較簡單的處理這個問題,可是在拿出這些Keys的時候,客戶端的內存佔用可能會比較大,尤爲是有大量符合條件的緩存項的時候。
涉及緩存的諸多操做(包含根據前綴去刪除緩存項),我也在EasyCaching中實現了相應的操做,後面也會不斷的抽時間來完善這一項目,有興趣的朋友能夠關注一下。
文中的示例代碼 RedisBatchRemoveSolution