使用RedisTemplate進行批量查詢時,為什么返回的結果會是空值?

使用RedisTemplate進行批量查詢時,為什么返回的結果會是空值?

redisTemplate批量查詢返回空值原因及解決方案

使用JavaredisTemplate進行Redis管道(pipeline)批量查詢時,經常會遇到一個棘手的問題:即使keys集合包含有效數據,Redis中也存在對應數據,但返回結果卻全是NULL。這是因為RedisTemplate的管道操作的特性導致的。

問題根源:

RedisTemplate的管道操作會將多個Redis命令批量發送到服務器,但不會立即返回結果。所有命令的執行結果會被緩存,直到調用executePipelined方法后,才一次性從服務器接收響應,并返回一個包含每個命令響應的列表。 因此,在RedisCallback或SessionCallback內部直接處理結果是無效的,因為此時Redis的響應尚未返回。

錯誤代碼示例 (類似原文中的錯誤代碼):

以下代碼片段演示了錯誤的處理方式,它試圖在管道操作內部處理結果:

// 錯誤示例:在pipeline內部嘗試處理結果 public <T> List<T> batchGetList(Collection<String> keys) {     List<T> list = new ArrayList<>();     // ... (省略部分代碼) ...     List<Object> results = redisTemplate.executePipelined(new RedisCallback<Object>() {         @Override         public Object doInRedis(RedisConnection connection) throws DataAccessException {             for (String key : keys) {                 byte[] bytes = connection.get(redisTemplate.getKeySerializer().serialize(key));                 T obj = (T) redisTemplate.getValueSerializer().deserialize(bytes); // 錯誤:結果尚未返回                 list.add(obj);             }             return null;         }     });     return list; }

正確解決方案:

正確的做法是在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 = redisTemplate.getKeySerializer();         for (String key : keys) {             connection.get(keySerializer.serialize(key));         }         return null; // executePipelined需要返回null     });      // 在管道執行之后處理結果     List<T> resultList = results.stream()             .map(result -> {                 if (result != null) {                     return (T) redisTemplate.getValueSerializer().deserialize((byte[]) result);                 } else {                     return null; // 處理null結果                 }             })             .collect(Collectors.toList());      return resultList; }

這段代碼首先執行管道操作,然后遍歷results列表,使用redisTemplate.getValueSerializer()對每個byte[]結果進行反序列化。 添加了對null結果的處理,以避免NullPointerException。 確保你的RedisTemplate配置了正確的序列化器。

關鍵點:

  • executePipelined的返回值: executePipelined方法返回一個包含所有命令執行結果的列表。 在Lambda表達式中返回null是必要的。
  • 結果處理位置: 結果處理必須在executePipelined調用之后進行。
  • 序列化器: 確保RedisTemplate配置了正確的鍵和值序列化器,以匹配你存儲在Redis中的數據類型
  • 空值處理: 對results列表中的null值進行處理,防止出現異常。

通過以上改進,可以有效解決RedisTemplate管道批量查詢返回空值的問題。 記住,管道操作的效率提升來自于批量執行,結果處理必須在批量操作完成之后進行。

? 版權聲明
THE END
喜歡就支持一下吧
點贊13 分享