本文记录 Spring Boot 中,如何用模式匹配的方式,批量扫描键值对:

扫描需要的keys

public static Set<String> scan(String key, RedisTemplate redisTemplate) {
        Set<String> res = new HashSet<>();
        try {
            ScanOptions scanOptions = ScanOptions.scanOptions().match(key + "*").count(1000).build();
            return (Set<String>) redisTemplate.execute((RedisCallback<Set<String>>) connection -> {
                Cursor<byte[]> cursor = connection.scan(scanOptions);
                while (cursor.hasNext()) {
                    String k = new String(cursor.next());
                    res.add(k);
                }
                return res;
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
        return res;
    }

扫描需要的keys并以Map 形式返回对应的k-v

/**
     * 实现一个根据 key 模式获取多个 key-value 对应数据的方法
     * @param key
     * @param redisTemplate
     * @return
     */
    public static Map<String, String> scanAndGet(String key, RedisTemplate redisTemplate) {
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);

        Map<String, String> res = new HashMap<>();
        try {
            ScanOptions scanOptions = ScanOptions.scanOptions().match(key + "*").count(1000).build();
            return (Map<String, String>) redisTemplate.execute((RedisCallback<Map<String, String>>) connection -> {
                Cursor<byte[]> cursor = connection.scan(scanOptions);
                while (cursor.hasNext()) {
                    String k = new String(cursor.next());
                    byte[] v = connection.get(k.getBytes(StandardCharsets.UTF_8));
                    
                    // 反序列化
                    String thisStr = (String) jackson2JsonRedisSerializer.deserialize(v);
                    res.put(k, thisStr);
                }
                return res;
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
        return res;
    }

这里需要注意:在返回 k-v 时,需要对 v 进行一步序列化操作,因为 ScanOptions 没有走我们的 Redis 配置,也就是不会自动进行反序列化。

如果没有手动反序列化,拿到的字符串可能是这样的:

"{\"author\":\"V_红星新闻\"}" 

这样是不可用的。

必须手动去除转义和前后的双引号,或者直接用反序列化器来解决。

手动去除代码示例:

String v = new String(connection.get(k.getBytes(StandardCharsets.UTF_8)));
String thisStr = "";
if (v != null) {
    // 字节数组转字符串后,出现了转义字符,这里将转义字符删除,并将前后的双引号删除
    thisStr = StringEscapeUtils.unescapeJava(v);
    if (thisStr.startsWith("\"") && thisStr.endsWith("\"")) {
        thisStr = thisStr.substring(1, thisStr.length()-1);
    }
}
Last modification:April 2nd, 2021 at 04:02 pm
请作者喝杯肥宅快乐水吧!