使用RedisTemplate和Pipeline批量查詢時(shí)返回值為空的原因是什么?如何解決這一問(wèn)題?

使用RedisTemplate和Pipeline批量查詢時(shí)返回值為空的原因是什么?如何解決這一問(wèn)題?

spring Data redis: redisTemplate與Pipeline批量查詢返回值為空的解決方法

使用Spring Data Redis的RedisTemplate進(jìn)行批量查詢時(shí),尤其采用pipeline模式,經(jīng)常會(huì)遇到返回值為空的情況。即使確認(rèn)Redis中存在對(duì)應(yīng)數(shù)據(jù),問(wèn)題依舊存在。本文將分析原因并提供解決方案。

問(wèn)題根源:Pipeline操作結(jié)果處理時(shí)機(jī)錯(cuò)誤

pipeline模式下,Redis命令并非立即執(zhí)行并返回結(jié)果,而是批量發(fā)送,批量接收。 錯(cuò)誤的處理方式通常在pipeline執(zhí)行過(guò)程中嘗試獲取結(jié)果,而此時(shí)結(jié)果尚未返回。

錯(cuò)誤示例:在pipeline內(nèi)部處理結(jié)果

以下代碼片段演示了錯(cuò)誤的處理方式:嘗試在RedisCallback或SessionCallback內(nèi)部直接反序列化結(jié)果。

// 錯(cuò)誤示例:在pipeline內(nèi)部處理結(jié)果 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(keySerializer.serialize(key)); // 獲取字節(jié)數(shù)組                 T value = (T) valueSerializer.deserialize(bytes); // 立即反序列化,錯(cuò)誤!                 list.add(value);              }             return null; // 返回null,pipeline結(jié)果被忽略         }     });     return list; // 返回空列表 }

正確方法:在pipeline執(zhí)行完畢后處理結(jié)果

executePipelined方法返回一個(gè)List,包含每個(gè)命令的執(zhí)行結(jié)果。正確的做法是在executePipelined之后處理這些結(jié)果。

解決方案:正確處理Pipeline結(jié)果

以下代碼展示了正確的處理方式:

public <T> List<T> batchGetList(Collection<String> keys) {     if (CollectionUtil.isEmpty(keys)) {         return new ArrayList<>();     }      RedisSerializer<String> keySerializer = redisTemplate.getStringSerializer();     RedisSerializer<T> valueSerializer = redisTemplate.getValueSerializer();      List<byte[]> results = redisTemplate.executePipelined((RedisConnection connection) -> {         for (String key : keys) {             connection.get(keySerializer.serialize(key));         }         return null; // 返回null,pipeline結(jié)果在results中     });      return results.stream()                   .map(bytes -> valueSerializer.deserialize(bytes))                   .collect(Collectors.toList()); }

這段代碼首先執(zhí)行pipeline操作,將所有g(shù)et命令發(fā)送到Redis。然后,在executePipelined返回后,遍歷結(jié)果列表,使用valueSerializer反序列化每個(gè)byte[]數(shù)組,最終得到正確的結(jié)果列表。

關(guān)鍵點(diǎn)總結(jié):

  • Pipeline的本質(zhì): 批量發(fā)送命令,批量接收結(jié)果,不是逐個(gè)命令執(zhí)行和返回。
  • 結(jié)果處理時(shí)機(jī): 在executePipelined方法返回后處理結(jié)果,而不是在pipeline操作內(nèi)部。
  • 序列化/反序列化: 使用RedisTemplate的序列化器進(jìn)行正確的序列化和反序列化操作。

通過(guò)以上方法,可以有效解決RedisTemplate和pipeline批量查詢時(shí)返回值為空的問(wèn)題,確保獲取到正確的數(shù)據(jù)。 請(qǐng)根據(jù)實(shí)際數(shù)據(jù)類型選擇合適的序列化器。

? 版權(quán)聲明
THE END
喜歡就支持一下吧
點(diǎn)贊10 分享