一、背景
在搭建了项目之后,由于需要通过触发动作,并删除redis中多个key。
二、思路
在查询了jedis并没有类似的删除方法之后,事情就变得清晰起来。完成上述任务,分为两个步骤:
第一,找到要删除的key;
第二,删除掉他们。
三、 解决方法
从找到要删除的key来说,有两种方法,一种是通过jedis的keys方法来获得;另外一种是通过scan方法获得。
1. keys
使用keys方法,寻找包含指定参数的key,其中“*”是匹配符,要是想找前缀就在其后加*,要是找后缀就在传入参数后面加*,而要是图省事方便,前后加*即可。
1 2 3 4 5 6 7 8 9 10 |
|
2. scan
使用scan方法,寻找包含指定参数的key,其中
第一,需要构建ScanParams(redis.clients.jedis.ScanParams);
第二,主要是填充两个参数第一个是match,标明需要匹配的字符串,第二个是count标明要扫描出多少个来,我这里写的是1000,因为目前库中keys远小于1000,相当于全找出来;
第三,jedis中的部分scan方法是@Deprecated的不建议使用。
在获得结果集之后,转换出来即可
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
因为,大家都知道keys的方法会阻塞单线程的redis。
在keys少的时候,无所谓,但是在keys多的时候,这个就会是很大的隐患。我们采用redis 就是为了其查询速度快。所以,决定采取后者scan的方法实现。
1 public void delStrings(String key) { 2 3 try { 4 Jedis jedis = jedisPool.getResource(); 5 // 存入键值对 6 ScanParams scanParams = new ScanParams(); 7 StringBuilder paramKey = new StringBuilder("*").append(key).append("*"); 8 scanParams.match(paramKey.toString()); 9 scanParams.count(1000); 10 ScanResult<String> sr = jedis.scan("0", scanParams); 11 List<String> a = sr.getResult(); 12 for (String delkey : a) { //循环一个一个的删除 13 jedis.del(delkey); 14 } 15 jedis.close(); 16 } catch (Exception e) { 17 // TODO: handle exception 18 } 19 }
四、MAVEN的依赖
1 2 3 4 5 |
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
jedis方式,到此结束
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
五、扩展——springboot中redisTemplate中使用lua脚本
RedisTemplate 已经封装了关于 set/hash/sorted set 的scan
redisTemplate.opsForHash().scan();
redisTemplate.opsForSet().scan();
redisTemplate.opsForZSet().scan();
下面介绍使用scan配合lua脚本进行删除。
① lua 脚本
local function scan(key)
local cursor = 0
local keynum = 0
repeat
local res = redis.call("scan", cursor, "match", key,'COUNT',ARGV[1])
if (res ~= nil and #res >= 0) then
redis.replicate_commands()
cursor = tonumber(res[1])
local ks = res[2]
keynum = #ks
for i=1,keynum,1 do
local k = tostring(ks[i])
redis.call("del", k)
end
end
until (cursor <= 0)
return keynum
end
local a = #KEYS
local b = 1
local total = 0
while (b <= a)
do
total = total + scan(KEYS[b])
b = b + 1
end
return total
1、key [key ...]: 表示在脚本中所用到的那些 Redis 键(key),这些键名参数可以在 Lua 中通过全局变量 KEYS 数组,用 1 为基址的形式访问( KEYS[1] , KEYS[2] ,以此类推)。
2、arg [arg ...]: 附加参数,在 Lua 中通过全局变量 ARGV 数组访问,访问的形式和 KEYS 变量类似( ARGV[1] 、 ARGV[2] ,诸如此类)。
② springboot 中使用RedisTemplate执行脚本,测试通过
String del = "local function scan(key)\n" +
" local cursor = 0\n" +
" local keynum = 0\n" +
"\n" +
" repeat\n" +
" local res = redis.call(\"scan\", cursor, \"match\", key,'COUNT',ARGV[1])\n" +
"\n" +
" if (res ~= nil and #res >= 0) then\n" +
" redis.replicate_commands()\n" +
" cursor = tonumber(res[1])\n" +
" local ks = res[2]\n" +
" keynum = #ks\n" +
" for i=1,keynum,1 do\n" +
" local k = tostring(ks[i])\n" +
" redis.call(\"del\", k)\n" +
" end\n" +
" end\n" +
" until (cursor <= 0)\n" +
"\n" +
" return keynum\n" +
"end\n" +
"\n" +
"local a = #KEYS\n" +
"local b = 1\n" +
"local total = 0\n" +
"while (b <= a)\n" +
"do\n" +
" total = total + scan(KEYS[b])\n" +
" b = b + 1\n" +
"end\n" +
"\n" +
"return total";
System.out.println(del);
//KEY[1] 为要删除的前缀 举例为 Test.* 代表以Test.开头的所有Key
//ARGV[1] 单次遍历的数量 注意 不是返回的数量,举例 服务器总共Key有10万 设置为20000则需要循环5次才能全部遍历完
// 指定 lua 脚本,并且指定返回值类型
DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(del, Long.class);
// 参数一:redisScript,参数二:key列表,参数三:arg(可多个)
Long result = (Long) redisTemplate.execute(redisScript, Collections.singletonList("myServiceCache*"),1000);
System.out.println(result);
附加:
redis 中执行 使用eval命令执行lua脚本
1、redis-cli命令 连接redis
2、使用eval命令
127.0.0.1:6379> eval "local function scan(key) local cursor = 0 local keynum = 0 repeat local res = redis.call("scan", cursor, "match", key,'COUNT',ARGV[1]) if (res ~= nil and #res >= 0) then redis.replicate_commands() cursor = tonumber(res[1]) local ks = res[2] keynum = #ks for i=1,keynum,1 do local k = tostring(ks[i]) redis.call("del", k) end end until (cursor <= 0) return keynum end local a = #KEYS local b = 1 local total = 0 while (b <= a) do total = total + scan(KEYS[b]) b = b + 1 end return total" 1 loadU* , 1000
Invalid argument(s)
127.0.0.1:6379>
3、但是出现报错,带解决。有了解的大神,还望不吝赐教。
链接:http://events.jianshu.io/p/5a95a8209e5b
转载自:
在spring boot上基于maven使用redis——批量匹配并删除 (二) - 幻xiang - 博客园
Redis:使用scan配合lua脚本进行删除key - 简书