在Spring中使用Redis Lua腳本批量刪除緩存

背景

  以前分享了一篇利用lua腳本批量刪除redis的key的文章.如今項目中我打算使用spring的緩存,而Spring緩存之前我是用ehcache來作實現的.沒發現什麼問題..此次我換成redis來作緩存了..通常也沒什麼大問題...目前惟一遇到的一個比較坑的問題就是緩存經過註解刪除不了..我想一想好像也算正常吧.由於java裏面作緩存的話可能會使用map相似的結構,我remove掉一個key,無論對應的value是什麼結構都能刪除掉..可是redis的key是沒有層級的...好比2個key分別是a:a1和a:a2.雖然可視化工具上看上去都是屬於a下面的..可是redis的del a並不會刪除a下屬的全部key而是隻會刪除key爲a的這個數據.因此我得本身實現Spring Cache中刪除緩存的那部分邏輯.而redis自己是沒有批量刪除key的功能的.html

 

問題

  因此如今的問題就是 如何在Spring的redisTemplate中使用lua腳本刪除keyjava

 

解決辦法

我以爲能夠這麼作:redis

1.首先把以前文章寫的批量刪除的lua腳本放到maven項目的resources下.spring

2.而後寫一個Bean implements InitializingBean在啓動的時候加載這些腳本.緩存

 1     /**
 2      * 加載批量lua腳本
 3      *
 4      * @throws Exception
 5      */
 6     @Override
 7     public void afterPropertiesSet() throws Exception {
 8         loadDelScript();
 9     }
10 
11     /**
12      * 加載批量刪除腳本
13      */
14     private void loadDelScript() throws IOException {
15         String s = FileUtils.readFileToString(new ClassPathResource(CRedisCacheConstant.SCRIPT_PATH + "/" + "dels.lua").getFile(), Charset.forName("UTF-8"));
16         DefaultRedisScript<List> sc = new DefaultRedisScript<>(s, List.class);
17         scripts.put("dels", sc);
18     }

3.須要批量刪除的時候經過DefaultRedisScript去使用這個腳本網絡

1 DefaultRedisScript<List> sc = scripts.get("dels");
2 List<String> cache = (List<String>) redisTemplate.execute(sc, stringRedisSerializer, stringRedisSerializer, Collections.singletonList(wholeKey));
3                     log.info("刪除page緩存 {}", cache);

這樣就能夠在Java代碼中使用lua腳本成功批量刪除緩存啦.maven

 

有些小朋友可能會問.這樣作每次都須要把腳本序列化傳給redis嗎?那腳本大了不是很佔用網絡嗎?ide

其實並不會...工具

 

DefaultScriptExecutor中有一段代碼:lua

 1     protected <T> T eval(RedisConnection connection, RedisScript<T> script, ReturnType returnType, int numKeys,
 2             byte[][] keysAndArgs, RedisSerializer<T> resultSerializer) {
 3 
 4         Object result;
 5         try {
 6             result = connection.evalSha(script.getSha1(), returnType, numKeys, keysAndArgs);
 7         } catch (Exception e) {
 8 
 9             if (!exceptionContainsNoScriptError(e)) {
10                 throw e instanceof RuntimeException ? (RuntimeException) e : new RedisSystemException(e.getMessage(), e);
11             }
12 
13             result = connection.eval(scriptBytes(script), returnType, numKeys, keysAndArgs);
14         }
15 
16         if (script.getResultType() == null) {
17             return null;
18         }
19 
20         return deserializeResult(resultSerializer, result);
21     }

會先計算這個腳本的sha1的值,經過redis的EVALSHA去容許腳本..若是失敗了,好比第一次沒有加載.就把腳本序列化傳過去執行...日後都經過這個sha1值直接調用.

127.0.0.1:6379> SCRIPT EXISTS f7cb6ede3d6d2e14b812f32f129633443197b42c
1) (integer) 1

 

小結

經過使用DefaultRedisScript能夠比較方便的在java中使用lua腳本操做redis

相關文章
相關標籤/搜索