redisTemplate批量查询返回空值问题详解及解决方案
使用redisTemplate进行批量查询时,经常会遇到返回结果为空的情况,即使Redis中存在对应数据。这通常是由于未正确处理管道操作的结果导致的。本文将深入探讨这个问题,并提供有效的解决方案。
问题描述
假设我们有一个方法batchGetList,使用RedisTemplate.executePipelined进行批量获取Redis数据:
问题代码示例(存在问题的代码):
public <T> List<T> batchGetList(Collection<String> keys) { List<T> list = new ArrayList<>(); if (CollectionUtil.isEmpty(keys)) { return list; } // ... (此处省略了不正确的管道操作代码) ... return list; }
在执行上述代码后,返回结果为空。即使keys集合包含有效键,Redis中也存在对应的数据。
问题原因分析
RedisTemplate.executePipelined方法执行管道操作,Redis命令的执行结果不会立即返回,而是批量执行后一起返回。 问题代码中,尝试在executePipelined内部处理每个命令的结果,这是无效的,因为此时结果尚未返回。
正确的解决方案
正确的做法是在executePipelined之后处理返回的结果列表。 以下代码展示了正确的实现方式:
public <T> List<T> batchGetList(Collection<String> keys) { if (CollectionUtil.isEmpty(keys)) { return new ArrayList<>(); } RedisSerializer<String> keySerializer = redisTemplate.getKeySerializer(); List<Object> results = redisTemplate.executePipelined((RedisConnection connection) -> { for (String key : keys) { connection.get(keySerializer.serialize(key)); } return NULL; // executePipelined需要返回null }); // 在管道执行外部处理结果 return results.stream() .map(result -> (T) redisTemplate.getValueSerializer().deserialize((byte[]) result)) .Filter(Objects::nonNull) //过滤掉null值 .collect(Collectors.toList()); }
代码说明:
-
RedisSerializer
keySerializer = redisTemplate.getKeySerializer(); : 获取RedisTemplate的键序列化器,确保键的正确序列化。 -
redisTemplate.executePipelined((RedisConnection connection) -> { … });: 将所有get命令放入管道中批量执行。 return null; 是executePipelined方法的要求。
-
results.stream().map(…)…collect(Collectors.toList());: 在管道执行完成后,使用Java Stream API处理结果列表。 map操作将byte[]类型的结果反序列化为目标类型T。filter(Objects::nonNull) 用于过滤掉可能存在的空值。
此方法确保所有get命令作为一个批量操作发送,并在操作完成后一次性处理所有结果,避免了返回值为空的问题。 请注意,此代码假设所有键对应的值可以使用相同的反序列化器进行反序列化。如果你的应用场景中存在不同类型的值,可能需要更复杂的处理逻辑来正确反序列化它们。
通过这个改进后的代码,可以有效解决RedisTemplate批量查询返回空值的问题,提高代码效率和可靠性。