当前位置:   article > 正文

Redis - 使用scan代替keys与hgetall操作_redis scan和getall

redis scan和getall

1.scan前言

当我们使用 keys * 或 hgetall 进行查询的时候会进行堵塞,导致 redis 整体不可用(因为redis是单线程的),而使用 scan 命令则不会。

从Redis v2.8开始,SCAN命令已经可用,它允许使用游标从keyspace中检索键。
对比KEYS命令,虽然SCAN无法一次性返回所有匹配结果,但是却规避了阻塞系统这个高风险,从而也让一些操作可以放在主节点上执行。

2.SCAN相关命令

  • SCAN相关命令包括SSCAN 命令、HSCAN 命令和 ZSCAN 命令,分别用于集合、哈希键及有序集等
  1. SCAN 命令用于迭代当前数据库中的数据库键。
  2. SSCAN 命令用于迭代集合键中的元素。
  3. HSCAN 命令用于迭代哈希键中的键值对。
  4. ZSCAN 命令用于迭代有序集合中的元素(包括元素成员和元素分值)。
  1. 因为 SCAN 、 SSCAN 、 HSCAN 和 ZSCAN 四个命令的工作方式都非常相似, 要记住:
  2. SSCAN 命令、 HSCAN 命令和 ZSCAN 命令的第一个参数总是一个数据库键。
  3. 而 SCAN 命令则不需要在第一个参数提供任何数据库键 —— 因为它迭代的是当前数据库中的所有数据库键。

 

3.基本用法:

命令格式:

SCAN cursor [MATCH pattern] [COUNT count]


命令解释:scan 游标 MATCH <返回和给定模式相匹配的元素> count 每次迭代所返回的元素数量


SCAN命令是增量的循环,每次调用只会返回一小部分的元素。所以不会有KEYS命令的坑(key的数量比较多,一次KEYS查询会block其他操作)。  
SCAN命令返回的是一个游标,从0开始遍历,到0结束遍历。
通过scan中的MATCH <pattern> 参数,可以让命令只返回和给定模式相匹配的元素,实现模糊查询的效果

  1. 示例:
  2. scan 0 match DL* count 5
  3. sscan myset 0 match f*

f

返回值解释:

SCAN 命令、 SSCAN 命令、 HSCAN 命令和 ZSCAN 命令都返回一个包含两个元素的 multi-bulk 回复

  • 回复的第一个元素是字符串表示的无符号 64 位整数(游标)
  1. SCAN 命令每次被调用之后, 都会向用户返回一个新的游标, 用户在下次迭代时需要使用这个新游标作为 SCAN 命令的游标参数, 以此来延续之前的迭代过程。
  2. 当 SCAN 命令的游标参数被设置为 0 时, 服务器将开始一次新的迭代, 而当服务器向用户返回值为 0 的游标时, 表示迭代已结束。
  • 回复的第二个元素是另一个 multi-bulk 回复
这个 multi-bulk 回复包含了本次被迭代的元素。

4、注意

SCAN命令不能保证每次返回的值都是有序的,另外同一个key有可能返回多次,不做区分,需要应用程序去处理。

SCAN 命令返回的每个元素都是一个数据库键。
SSCAN 命令返回的每个元素都是一个集合成员。
HSCAN 命令返回的每个元素都是一个键值对,一个键值对由一个键和一个值组成。
ZSCAN 命令返回的每个元素都是一个有序集合元素,一个有序集合元素由一个成员(member)和一个分值(score)组成。

5、Jedis实现

  1. /**
  2. * @Description: 实现hscan dowhile形式
  3. * @Author: zongx
  4. * @Date: 2020/3/6
  5. * @Param: pattern
  6. * @return java.util.List<java.lang.String>
  7. */
  8. public Map<String,String> hscan(final String key,final String pattern) {
  9. return execute(new JedisAction<Map<String,String>>() {
  10. @Override
  11. public Map<String, String> action(Jedis jedis) {
  12. // 游标初始值为0
  13. String cursor = ScanParams.SCAN_POINTER_START;
  14. ScanParams scanParams = new ScanParams();
  15. scanParams.match(pattern);
  16. scanParams.count(Integer.MAX_VALUE);
  17. Map<String, String> results = new HashedMap();
  18. do {
  19. ScanResult<Map.Entry<String, String>> hscanResult =
  20. jedis.hscan(key, String.valueOf(cursor), scanParams);
  21. for (Map.Entry<String, String> en : hscanResult.getResult()) {
  22. results.put(en.getKey(),en.getValue());
  23. }
  24. //获取游标位置,若大于0,则代表还有数据,需要继续迭代
  25. cursor = hscanResult.getStringCursor();
  26. } while (Integer.parseInt(cursor) > 0);
  27. return results;
  28. }});
  29. }
  30. /**
  31. *scan,while形式
  32. * @param pattern
  33. * @param count
  34. * @return
  35. */
  36. public List<String> scan(final String pattern, final int count) {
  37. return execute(new JedisAction<List<String>>() {
  38. @Override
  39. public List<String> action(Jedis jedis) {
  40. ScanParams params = new ScanParams();
  41. params.match(pattern);
  42. params.count(count);
  43. String cursor = "0";
  44. List<String> results = new ArrayList<>();
  45. while (true) {
  46. ScanResult scanResult = jedis.scan(cursor, params);
  47. List<String> elements = scanResult.getResult();
  48. if (elements != null && elements.size() > 0) {
  49. results.addAll(elements);
  50. }
  51. cursor = scanResult.getStringCursor();
  52. if ("0".equals(cursor)) {
  53. break;
  54. }
  55. }
  56. return results;
  57. }
  58. });
  59. }

代码还可以参考:

https://www.xttblog.com/?p=3635

工具类在下载中心可以下载

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Guff_9hys/article/detail/735613
推荐阅读
相关标签
  

闽ICP备14008679号