为什么Java通过redisTemplate使用Pipeline批量查询拿到的值都是空?

redisTemplate使用Pipeline批量查询,返回的结果全是null,keys集合是有数据的,redis里也是有数据的

public <T> List<T> batchGetList(Collection<String> keys) {
        List<T> list = new ArrayList<>();
        if (CollectionUtil.isEmpty(keys)) {
            return list;
        }
        // 自定义序列化
        RedisSerializer stringSerializer = redisTemplate.getStringSerializer();
        RedisSerializer valueSerializer = redisTemplate.getValueSerializer();
        RedisSerializer defaultSerializer = redisTemplate.getDefaultSerializer();
        List result = redisTemplate.executePipelined(new RedisCallback<Object>() {
            @Override
            public Object doInRedis(RedisConnection connection) throws DataAccessException {
                for (String k : keys) {
                    System.err.println(k);
                    byte[] bytes = connection.get(stringSerializer.serialize(k));
                    byte[] bytes1 = connection.get(defaultSerializer.serialize(k));
                    byte[] bytes2 = connection.get(valueSerializer.serialize(k));
                    System.err.println(Arrays.toString(bytes));
                    System.err.println(Arrays.toString(bytes1));
                    System.err.println(Arrays.toString(bytes2));
                    Object deserialize = defaultSerializer.deserialize(bytes);
                    System.err.println(deserialize);
                    list.add((T) deserialize);
                }
                return null;
            }
        }, redisTemplate.getValueSerializer());
        return list;
    }

image.png

换了一种方式,返回还是null

public <T> List<T> batchGetList1(Collection<String> keys) {
        List<T> list = new ArrayList<>();
        if (CollectionUtil.isEmpty(keys)) {
            return list;
        }
        List result = redisTemplate.executePipelined(new SessionCallback<Object>() {
            @Override
            public Object execute(RedisOperations operations) throws DataAccessException {
                keys.forEach(key->{
                    System.err.println(key);
                    Object o = operations.opsForValue().get(key);
                    System.err.println(o);
                    list.add((T) o);
                });
                return null;
            }
        });
        return list;
    }

image.png

阅读 2.6k
1 个回答
✓ 已被采纳

在使用Spring Data Redis的RedisTemplate进行批量操作时,如果遇到使用管道(Pipeline)查询但返回的结果全是null,同时确认keys集合中确实有数据并且Redis中也有对应的数据,这通常是由于对管道操作的结果处理不当导致的。

首先,需要明白在使用管道技术时,Redis命令的执行结果不会立即返回。所有的命令都会被缓存起来,直到调用executePipelined方法时才一次性发送给Redis服务器,而executePipelined方法本身会返回一个包含每个命令响应的List。这就是为什么你的第一个示例方法中尝试在管道操作内部处理命令结果(例如直接反序列化)不会奏效的原因。管道操作完成后,你应该处理executePipelined返回的结果列表。

此外,你的第一个方法示例中尝试在循环内对每个键进行获取并反序列化,这实际上违背了使用管道的初衷,因为这样做并没有减少网络往返次数,而且实际上doInRedis方法的返回值应该被用来处理所有命令的结果。

对于第二个示例,正确的做法是在executePipelined之后处理结果,而不是在管道操作内部。

public <T> List<T> batchGetList(Collection<String> keys) {
    if (CollectionUtil.isEmpty(keys)) {
        return new ArrayList<>();
    }

    List<Object> results = redisTemplate.executePipelined((RedisConnection connection) -> {
        RedisSerializer<String> keySerializer = (RedisSerializer<String>) redisTemplate.getKeySerializer();
        for (String key : keys) {
            connection.get(keySerializer.serialize(key));
        }
        return null;
    });

    // 在管道执行外部处理结果
    return results.stream()
                  .map(result -> (T) redisTemplate.getValueSerializer().deserialize((byte[]) result))
                  .collect(Collectors.toList());
}

这个方法发送所有的GET命令作为一个批量操作,并在操作完成后一次性处理所有的结果。请注意,这里假设所有键对应的值都是可以使用相同的反序列化器反序列化的。如果你的应用场景中有不同类型的值,你可能需要对结果进行进一步的处理来正确地反序列化它们。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题