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ù)類型選擇合適的序列化器。