Redis 序列化值,多了雙引號(hào)問題
問題
有兩個(gè)服務(wù):A 服務(wù)和 B 服務(wù),A 服務(wù)負(fù)責(zé)將數(shù)據(jù)寫入 Redis 的 Hash 中,B 服務(wù)負(fù)責(zé)從 Redis 中讀取這些數(shù)據(jù)。在實(shí)際運(yùn)行中,B 服務(wù)讀取到的數(shù)字類型字符串與 A 服務(wù)寫入的值不一致:
圖片
問題排查,最終發(fā)現(xiàn)通過hgetall命令返回字符串多加了有引號(hào):
圖片
這里懷疑可能是Redis配置中的序列化參數(shù)設(shè)置導(dǎo)致的
序列化與反序列化
Redis序列化和反序列化是將數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)換為二進(jìn)制格式和將二進(jìn)制數(shù)據(jù)轉(zhuǎn)換為對(duì)應(yīng)的數(shù)據(jù)結(jié)構(gòu)的過程。
序列化的作用是將數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)換為二進(jìn)制形式,以便于傳輸和存儲(chǔ)。它可以將數(shù)據(jù)保存在文件、數(shù)據(jù)庫或者網(wǎng)絡(luò)上,并能夠被其他程序使用。序列化還能夠?qū)?shù)據(jù)進(jìn)行壓縮,并提供靈活的數(shù)據(jù)交換格式。
反序列化則是將二進(jìn)制數(shù)據(jù)轉(zhuǎn)化為對(duì)應(yīng)的數(shù)據(jù)結(jié)構(gòu),方便在Redis內(nèi)部進(jìn)行存儲(chǔ)和查詢等操作。這樣可以實(shí)現(xiàn)對(duì)數(shù)據(jù)的讀取和寫入。
Redis支持多種數(shù)據(jù)結(jié)構(gòu)的序列化和反序列化,包括string、hash、list、set、zset。
SpringBoot提供了多種Redis序列化方式,包括JDK序列化、JSON序列化、FastJSON序列化、Jackson序列化、Protobuf序列化等。其中JDK序列化是默認(rèn)的序列化方式。
常見的序列化器
- StringRedisSerializer:用于字符串的序列化和反序列化。適用于簡單的字符串鍵值對(duì)。
- Jackson2JsonRedisSerializer:使用 Jackson 庫進(jìn)行 JSON 序列化和反序列化。適用于復(fù)雜對(duì)象的序列化。
- GenericJackson2JsonRedisSerializer:類似于 Jackson2JsonRedisSerializer,但可以處理泛型對(duì)象。
- OxmMarshaler:使用 Spring 的 Object-XML 映射功能進(jìn)行序列化和反序列化。適用于 XML 數(shù)據(jù)。
- GenericToStringSerializer:將對(duì)象轉(zhuǎn)換為字符串,適用于簡單的對(duì)象。
A服務(wù)
使用了Jackson2JsonRedisSerializer
private RedisTemplate<String, Object> createRedisTemplate(JedisConnectionFactory connectionFactory) {
// 序列化配置
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance , ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(connectionFactory);
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setDefaultSerializer(jackson2JsonRedisSerializer);
redisTemplate.setEnableDefaultSerializer(true);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
B服務(wù)
此服務(wù)為c++端,使用默認(rèn)String,該端不做調(diào)整的話,修復(fù)A端為new StringRedisSerializer()方式
測試
圖片
使用StringRedisSerializer來序列化key和value,這個(gè)序列化器會(huì)把Java字符串直接轉(zhuǎn)換為Redis存儲(chǔ)的字節(jié)序列,而不添加任何額外的格式化或引號(hào)。
使用Jackson2JsonRedisSerializer來序列化key和value,會(huì)把Java對(duì)象序列化為JSON格式的字符串。如果你序列化的是Java字符串,那么它就會(huì)被JSON格式化,并在最終存儲(chǔ)在Redis中時(shí)帶有雙引號(hào)。