8

SpringBoot中如何一次批量扫描Redis的键值对?

 3 years ago
source link: http://www.eknown.cn/index.php/%E4%B8%AD%E9%97%B4%E4%BB%B6/redis_scan.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

本文记录 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);
    }
}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK