Quarkus/Mutiny中实现Redis scan功能是否必须使用递归?
非递归Redis SCAN实现方案
响应式客户端(适配你现有Mutiny技术栈)
你当前使用的是Mutiny响应式框架,直接调用框架内置的repeat操作符即可替代递归实现,逻辑更简洁,同时避免递归深度过大引发的栈溢出风险,完整实现如下:
import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicReference; import io.smallrye.mutiny.Uni; // 初始化结果集合与游标变量 List<String> results = new ArrayList<>(); AtomicReference<String> cursor = new AtomicReference<>("0"); Uni<List<String>> scanUni = Uni.createFrom().deferred(() -> { // 每次执行都用最新游标构造请求参数 List<String> args = List.of(cursor.get(), "MATCH", "*"); return reactiveRedisClient.scan(args); }) // 配置重复执行规则 .repeat() .until(item -> { // 存储本次扫描到的键 List<?> keysPart = (List<?>) item.get(1); keysPart.forEach(k -> results.add(k.toString())); // 更新游标 cursor.set(item.get(0).toString()); // 游标返回0时终止循环 return "0".equals(cursor.get()); }) // 取最后一次执行结果,转换为返回最终扫描结果的Uni .last() .map(ignored -> results); // 订阅逻辑和原实现完全兼容 scanUni.subscribe().with(item -> LOGGER.info(item));
核心逻辑说明:
- 用
AtomicReference包装游标是因为Lambda表达式内只能引用final或等效final的变量,包装后可以自由修改内部存储的游标值 deferred操作符保证每次重复执行scan请求时,都会读取最新的游标值构造参数,不会复用第一次请求的参数- 所有循环逻辑都由框架内置操作符实现,没有自定义递归调用,可维护性更高
同步客户端通用实现
如果你使用的是同步Redis客户端(如Jedis),非递归实现更简单,直接用do-while循环即可:
import redis.clients.jedis.Jedis; import redis.clients.jedis.ScanParams; import redis.clients.jedis.ScanResult; import java.util.ArrayList; import java.util.List; List<String> results = new ArrayList<>(); String cursor = "0"; ScanParams params = new ScanParams().match("*"); do { ScanResult<String> scanResult = jedis.scan(cursor, params); results.addAll(scanResult.getResult()); cursor = scanResult.getCursor(); } while (!"0".equals(cursor)); LOGGER.info(results);
内容的提问来源于stack exchange,提问作者Charlie
相关产品推荐
相关产品推荐

