SpringBoot整合Redis开发-Java客户端操作Redis之使用SCAN代替KEYS命令-《Java笔记》

admin 2025-10-19 05:18:39 编程 来源:ZONE.CI 全球网 0 阅读模式

Java Redis SCAN KEYS

使用SCAN代替KEYS

  1. /**
  2. * redis扩展工具
  3. *
  4. * @author Fcant
  5. * @since 2020/2/21 23:35
  6. */
  7. public abstract class RedisHelper {
  8. private static Logger logger = LoggerFactory.getLogger(RedisHelper.class);
  9. /**
  10. * scan 实现
  11. *
  12. * @param redisTemplate redisTemplate
  13. * @param pattern 表达式,如:abc*,找出所有以abc开始的键
  14. */
  15. public static Set<String> scan(RedisTemplate<String, Object> redisTemplate, String pattern) {
  16. return redisTemplate.execute((RedisCallback<Set<String>>) connection -> {
  17. Set<String> keysTmp = new HashSet<>();
  18. try (Cursor<byte[]> cursor = connection.scan(new ScanOptions.ScanOptionsBuilder()
  19. .match(pattern)
  20. .count(10000).build())) {
  21. while (cursor.hasNext()) {
  22. keysTmp.add(new String(cursor.next(), "Utf-8"));
  23. }
  24. } catch (Exception e) {
  25. logger.error(e.getMessage(), e);
  26. throw new RuntimeException(e);
  27. }
  28. return keysTmp;
  29. });
  30. }
  31. }

源码分析

很多文章说这种实现方式cursor只会被执行一次,其实这是错误的,使用这种方式cursor会将所有的符合条件的key都返回回来,他只是将游标的移动给封装了起来而已,真正执行查询的语句起始在cursor.hasNext()里面,源码如下:

  1. /*
  2. * (non-Javadoc)
  3. * @see java.util.Iterator#hasNext()
  4. */
  5. @Override
  6. public boolean hasNext() {
  7. assertCursorIsOpen();
  8. // 存放结果集的容器没有值,并且游标状态是未完成的时候进行Scan动作
  9. while (!delegate.hasNext() && !CursorState.FINISHED.equals(state)) {
  10. scan(cursorId);
  11. }
  12. // 如果结果容器还有值直接返回true,进行循环
  13. if (delegate.hasNext()) {
  14. return true;
  15. }
  16. // 如果结果容器没有值,但是游标不为0则表示还有值,需要进行下一次循环
  17. if (cursorId > 0) {
  18. return true;
  19. }
  20. return false;
  21. }
  22. private void scan(long cursorId) {
  23. // 进行scan操作
  24. ScanIteration<T> result = doScan(cursorId, this.scanOptions);
  25. // 结果集处理
  26. processScanResult(result);
  27. }
  28. private void processScanResult(ScanIteration<T> result) {
  29. if (result == null) {
  30. // 重置结果集容器
  31. resetDelegate();
  32. // 设置游标状态为完成
  33. state = CursorState.FINISHED;
  34. return;
  35. }
  36. // 获取当前游标位置
  37. cursorId = Long.valueOf(result.getCursorId());
  38. if (isFinished(cursorId)) {
  39. // 游标返回0,设置游标状态为完成
  40. state = CursorState.FINISHED;
  41. }
  42. if (!CollectionUtils.isEmpty(result.getItems())) {
  43. // 将查询结果放到容器中
  44. delegate = result.iterator();
  45. } else {
  46. resetDelegate();
  47. }
  48. }

由上面源码可以看到游标的移动是在processScanResult()方法中完成。通过state来记录当前游标状态,大致过程为:

  1. 当存放结果集的容器没有值,并且游标状态是未完成的时候进行Scan动作
  2. 如果结果容器还有值直接返回true,进行循环
  3. 如果结果容器没有值,但是游标不为0则表示还有值,需要进行下一次循环
以太坊cppgolang区别 编程

以太坊cppgolang区别

以太坊是一种去中心化的开源平台,它采用智能合约技术,旨在构建和运行不受干扰的分布式应用程序。作为目前最受欢迎的区块链平台之一,以太坊提供了多种编程语言的支持,其
progolang 编程

progolang

Go语言(Golang)是由Google开发的一门静态类型编程语言。作为一名专业的Golang开发者,我深知这门语言的优势和特点。在本文中,我将介绍Golang
golangn个发送者 编程

golangn个发送者

Golang是一种开源的编程语言,由Google团队开发,旨在提高程序的并发性和简化软件开发过程。在Go语言中,有时需要向多个接收者发送信息。本文将介绍如何在G
golang技能图谱 编程

golang技能图谱

从互联网行业的快速发展到人工智能技术的日益成熟,各种编程语言也应运而生。而在这众多的编程语言中,Golang(即Go)作为一门强大且高效的开发语言备受关注。Go
评论:0   参与:  7