如何优雅地删除Redis set集合中前缀相同的key?
      Redis中有删除单条数据的命令DEL,却没有批量删除特定前缀key的指令,但我们经常遇到需要根据前缀来删除的业务场景,那么究竟该怎么做呢?可能你一通搜索后会得到下边的答案:
redis-cli --raw keys "prefix-*" | xargs redis-cli del

直接在linux下通过redis的keys命令匹配到所有的key,然后调用系统命令xargs来删除,看似十全十美,实则风险巨大。这就是一颗随时爆炸的炸弹!我们都知道Redis是单线程服务模式,使用命令 keys * 查询key的时候会阻塞正常的业务请求,甚至造成redis宕机,所以肯定不行。因此,我们在生产环境中应当避免使用上边的方法,那使用什么优雅的方法来解决呢?SCAN!

SCAN介绍

       Redis从2.8版本开始支持SCAN命令,它是一个基于游标的迭代器,每次被调用之后都会返回一个新的游标,用户在下次迭代时需要使用这个新游标作为SCAN命令的游标参数,以此来延续之前的迭代过程,直到服务器返回值为0的游标时,一次完整的遍历过程就结束了。
       SCAN命令的基本语法如下:
 
scan cursor [MATCH pattern] [COUNT count]

MATCH: 匹配规则,例如遍历以ops-coffee-开头的所有key可以写成ops-coffee-*,中间包含-coffee-的可以写成*-coffee-*cursor: 游标,

COUNT:  COUNT选项的作用就是让用户告知迭代命令,在每次迭代中应该从数据集里返回多少元素,COUNT只是对增量式迭代命令的一种提示,并不代表真正返回的数量,例如你COUNT设置为2有可能会返回3个元素,但返回的元素数据会与COUNT设置的正相关,COUNT的默认值是10。
     下面在jedis中操作scan和keys,以删除相同前缀的key。
 
public void testSetDel(Jedis jedis) {
try {
log.info("---------------- Tests begin -----------------");
initRedisData(jedis);
String givenKey = "prefix_*";
delValuesByKeys(givenKey, jedis); log.info("开始使用 scan 删除数据 ------------ ");
initRedisData(jedis);
this.delSetValues(givenKey, jedis); Set<String> keys = jedis.keys(givenKey);
log.info("---------------- Tests end ----------------- 是否存在相同前缀的key result = " + !CollectionUtils.isEmpty(keys));
} catch (Exception e) {
log.error(" 删除指定前缀的key对应的键值对 " + e);
} finally {
if (jedis != null) {
jedis.close();
log.info("关闭jedis连接");
}
}
}
/**
* java redis 删除指定前缀的key对应的键值对
* @param givenKey
* @return
*/
public Boolean delSetValues(String givenKey, Jedis jedis) throws Exception {
log.info("开始模糊删除set中的数据,givenKey = " + givenKey);
List<String> keys = getByScan(givenKey, jedis);
log.info("即将删除的key是 " + keys);
String[] array = keys.toArray(new String[0]);
jedis.del(array);
return true;
}
/**
* Jedis 删除指定前缀的key对应的key,使用keys
* @param givenKey
* @return
*/
public Boolean delValuesByKeys(String givenKey, Jedis jedis) throws Exception {
log.info("开始模糊删除set中的数据,givenKey = " + givenKey);
Set<String> keys = jedis.keys(givenKey);
for (String key : keys) {
log.info("当前 key 是 :" + key);
jedis.del(key);
}
return true;
}
private void initRedisData(Jedis jedis) {
jedis.set("prefix_1333", "1");
jedis.set("prefix_2KKKKK", "2");
jedis.set("prefix_3哈哈哈哈哈哈", "777");
}

// 使用 scan
public List<String> getByScan(String key, Jedis jedis) {
List<String> list = new ArrayList<>();
ScanParams params = new ScanParams();
params.match(key);
params.count(100);
String cursor = "0";
while (true) {
ScanResult scanResult = jedis.scan(cursor, params);
List<String> eles = scanResult.getResult();
if (!CollectionUtils.isEmpty(eles)) {
list.addAll(eles);
}
cursor = scanResult.getStringCursor();
if ("0".equals(cursor)) {
break;
}
}
log.info(" getByScan 查到的数据集是 ============ " + list);
return list;
}

测试结果:

---------------- Tests begin -----------------
开始模糊删除set中的数据,givenKey = prefix_*
当前 key 是 :prefix_1333
当前 key 是 :prefix_3哈哈哈哈哈哈
当前 key 是 :prefix_2KKKKK
开始使用 scan 删除数据 ------------
开始模糊删除set中的数据,givenKey = prefix_*
getByScan 查到的数据集是 ============ [prefix_1333, prefix_2KKKKK, prefix_3哈哈哈哈哈哈]
即将删除的key是 [prefix_1333, prefix_2KKKKK, prefix_3哈哈哈哈哈哈]
---------------- Tests end ----------------- 是否存在相同前缀的 key result = false
   总结:虽然不提倡使用keys命令删除key,但是,本文示例依然给出了示例,目的在于了解使用原理。当然,比使用scan命令删除key效果更好的方案是直接调用Lua脚本,童鞋们自己琢磨吧!
 

Redis删除相同前缀的key的更多相关文章

  1. laravel redis 删除指定前缀的 key

    // 前缀 $prefix = 'abc'; // 需要在前面连接上应用的缓存前缀 $keys = app('redis')->keys(config('cache.prefix') . $pr ...

  2. Redis删除特定前缀key的优雅实现

    还在用keys命令模糊匹配删除数据吗?这就是一颗随时爆炸的炸弹! Redis中没有批量删除特定前缀key的指令,但我们往往需要根据前缀来删除,那么究竟该怎么做呢?可能你一通搜索后会得到下边的答案 re ...

  3. redis删除指定前缀的缓存

    redis作为缓存服务器为MySQL数据库提供较高的防御性,对于一些数据的查询可以直接从缓存中可以进行查询. 但是,某些情况下,我们需要清除缓存. 以下场景: 公司经常做活动,每个活动都存在大量的数据 ...

  4. php redis 获取指定前缀的所有key

    php redis 获取指定前缀的所有key 以laravel框架为例: $key = $this->redis->keys('db:shipping:shippingId:' . &qu ...

  5. redis 删除大key集合的方法

    redis大key,这里指的是大的集合数据类型,如(set/hash/list/sorted set),一个key包含很多元素.由于redis是单线程,在删除大key(千万级别的set集合)的时候,或 ...

  6. redis删除单个key和多个key,ssdb会落地导致重启redis无法清除缓存

    redis删除单个key和多个key,ssdb会落地导致重启redis无法清除缓存,需要针对单个key进行删除 删除单个:del key 删除多个:redis-cli -a pass(密码) keys ...

  7. redis key全量导出与导出指定前缀的key

    redis命令列表中有两种方法可以全量导出所有的key: (1)keys 由于redis是单线程的,使用keys会导致redis服务阻塞,不建议线上服务采用这种方式. (2)scan 命令,下面是使用 ...

  8. reids中删除某个前缀的所有key

    需求:reids中删除某个前缀的所有key 说明:代码中的0:2标识从key前缀中截取前2个字符,这里示例的时候比如“b_”前缀,使用时候根据实际情况截取对应的长度进行判断即可. 生成测试数据 #!/ ...

  9. redis如何清除所有的key

    redis比memcache好的地方之一,如果memcache,恐怕就得关掉重启了. 1 使用cli FLUSHDB 清除一个数据库,FLUSHALL清除整个redis数据. 2 使用shell re ...

随机推荐

  1. maven一些简单常用却容易记混的命令参数-U -e -B

    install 命令完成了项目编译.单元测试.打包功能,同时把打好的可执行jar包(war包或其它形式的包)布署到本地maven仓库,但没有布署到远程Maven私服仓库: deploy 命令完成了项目 ...

  2. 在论坛中出现的比较难的sql问题:22(触发器专题3)

    原文:在论坛中出现的比较难的sql问题:22(触发器专题3) 最近,在论坛中,遇到了不少比较难的sql问题,虽然自己都能解决,但发现过几天后,就记不起来了,也忘记解决的方法了. 所以,觉得有必要记录下 ...

  3. 【es6】promise

    一.什么是promise?我们用promise解决什么样的问题 promise是异步编程的一种解决方案:从语法上来说,Promise是一个对象,从他可以获取异步操作的信息:从本意上讲,它是承诺,它承诺 ...

  4. laravel 中将一对多关联查询的结果去重处理

    先交代下数据表结构 主表(订单表)order数据 ord_id order_sn 1 EX2019100123458 其中主键为order_id(订单id) 子表(门票表)order_item数据 o ...

  5. js入门之字符串常用的方法

    一. 概念理解基本包装类型 1. 基本包装类型 三种基本包装类型 String var s = new String('123dddd'); Number Boolean 简单类型没有方法和属性 之所 ...

  6. 2019最新Web前端经典面试试题(含答案)

    1,阐述清楚浮动的几种方式(常见问题)(1)父级div定义 height原理:父级div手动定义height,就解决了父级div无法自动获取到高度的问题. 优点:简单.代码少.容易掌握 缺点:只适合高 ...

  7. iOS 数据源切换混乱问题

    问题场景 这个问题遇到是偶然的,正常来说是不会出现的.但是有时候在一些极端操作情况下,还是出现了. 现在我说明下这个场景.页面上是一个tableview,那对应的有一个dataSource,页面顶部有 ...

  8. 九、分组查询详解(group by & having)

    本篇内容 分组查询语法 聚合函数 单字段分组 多字段分组 分组前筛选数据 分组后筛选数据 where和having的区别 分组后排序 where & group by & having ...

  9. MySQL增删查改语句(入门)

    目录 create alter: insert delete update select 数据库定义语句: create:创建数据库及表对象 drop:删除数据库及表对象 alter:修改数据库及表对 ...

  10. servlet版本与tomcat版本对应关系,各版本web.xml头信息写法

    The mapping between the specifications and the respective Apache Tomcat versions is: Servlet Spec JS ...