在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

相关文章
相关标签/搜索