使用WireShark分析使用RedisTemplate取不到值的問題

滄海一滴發表於2019-03-05


現象:
使用Java Redis客戶端將資料存放到Redis後,使用redisTemplate卻不出來
原因:
Java Redis客戶端在將資料存放在Redis時,會對Key,Value,Field進行編碼。從Redis中取資料時,如果Key、Field的編碼和存放時不一樣,就會取不出來。
就像中文亂碼一樣,同樣的中文字串,存放時編碼格式不對,就不能被識別。

問題覆盤及分析過程:

(1)使用下面程式碼將資料放到Redis中

stringRedisTemplate.opsForHash().put("CATALOG_DEV","KEY_INDEX_CATALOG",JsonUtil.list2json(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")

使用wireshark抓包:
方式1時,HGET命令傳送到Redis伺服器的指令:


方式2時,HGET命令傳送到Redis伺服器的指令:

 

可見,雖然程式碼中,Redis的Java客戶端傳送的key和field都是相同和字串,但Redis接受到的Field卻是不同的。
看看Redis伺服器上存放的Field是什麼樣的:

 

 


看一個使用redisTemplate客戶端存放的資料:

對比看下方式1存放到Redsi伺服器上的資料


為什麼有這個差異呢?來看看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沒有指定,應該會走預設,如下圖所示:


StringRedisTemplate的例項化程式碼如下:

    @Bean
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

可以看到,HashKeySerializer、HashValueSerializer都使用了StringRedisSerializer,與上面的情況一致。O了

 

擴充套件:
WireShark抓包利器:
https://github.com/jzwinck/redis-wireshark

連結:https://pan.baidu.com/s/1M9tXDN54FODU7NftkLfwKQ
提取碼:kzhc
複製這段內容後開啟百度網盤手機App,操作更方便哦


檢視WireShark外掛配置目錄及已經配置外掛的資訊:

外掛copy到目錄:幫助--》關於--》資料夾--》Personal configuration


已經安裝的外掛列表:

 

相關文章