stringRedisTemplate
将数据存放到 Redis
后,使用 redisTemplate
却取不出来 !!!???
原因:
Java Redis客户端在将数据存放在Redis时,会对key,value,field进行编码。从Redis中取数据时,如果key、field的编码和存放时不一样,就会取不出来。 就像中文乱码一样,同样的中文字符串,存放时使用不同的编码,编码后的字符串之间就不equals了。
解决办法:
存取Redis中的数据时,发送的指令要使用相同的Serializer进行序列化/反序列化
问题复盘及分析过程:
(1)使用下面代码将数据放到 Redis
服务器
stringRedisTemplate.opsForHash().put("CATALOG_DEV","KEY_INDEX_CATALOG",list);
(2)使用方式1,可以 HGET
到的value和存放时的一致:
stringRedisTemplate.opsForHash().get("CATALOG_DEV","KEY_INDEX_CATALOG")
(3)使用方式2, HGET
得到的value是nulll:
redisTemplate.opsForHash().get("CATALOG_DEV","KEY_INDEX_CATALOG")
2. 抓包分析
使用Wireshark抓包:
方式1时, HGET
命令发送到 Redis
服务器的指令:
方式2时, HGET
命令发送到 Redis
服务器的指令:
由上可见,虽然代码中, Redis
的Java客户端发送的key和field都是相同的字符串,但 Redis
收到的field却是不同的。
3. 看看 Redis
服务器上存放的field是什么样的:
再来看一个使用 redisTemplate
客户端存放的数据:
对比看下方式1存放到 Redis
服务器上的数据
为什么有这个差异呢?来看看 Spring
容器中的 stringRedisTemplate
和 redisTemplate
实例有什么区别: RedisTemplate
的实例化代码如下:
@Bean
@SuppressWarnings({"rawtypes", "unchecked"})
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)
throws UnknownHostException {
RedisSerializer<String> stringSerializer = new StringRedisSerializer();
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
// 设置value的序列化采用Jackson2JsonRedisSerializer
template.setValueSerializer(jackson2JsonRedisSerializer);
// 设置key的序列化采用StringRedisSerializer
template.setKeySerializer(stringSerializer);
// template.setHashKeySerializer(stringSerializer);
// template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
HashKeySerializer
、 HashValueSerializer
没有指定,应该会使用默认的Serializer,
如下图所示:
StringRedisTemplate
的实例化代码如下:
@Bean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
可以看到, HashKeySerializer
、 HashValueSerializer
都使用了 StringRedisSerializer
,与上面的情况一致。O了
扩展:
1. WireShark抓Redis包的利器: https://github.com/jzwinck/redis-wireshark
上面用到的lua plugin已经上传到baidu网盘:
链接:https://pan.baidu.com/s/1M9tXDN54FODU7NftkLfwKQ 提取码:kzhc
2. 查看WireShark插件配置目录及已经配置插件的信息:
lua插件需要copy到的目录: 帮助--》关于--》文件夹--》Personal configuration
已经安装的插件列表: