问题
有两个服务:A 服务和 B 服务,A 服务负责将数据写入 Redis 的 Hash 中,B 服务负责从 Redis 中读取这些数据。在实际运行中,B 服务读取到的数字类型字符串与 A 服务写入的值不一致:
图片
问题排查,最终发现通过hgetall命令返回字符串多加了有引号:
图片
这里怀疑可能是Redis配置中的序列化参数设置导致的
序列化与反序列化
Redis序列化和反序列化是将数据结构转换为二进制格式和将二进制数据转换为对应的数据结构的过程。
序列化的作用是将数据结构转换为二进制形式,以便于传输和存储。它可以将数据保存在文件、数据库或者网络上,并能够被其他程序使用。序列化还能够对数据进行压缩,并提供灵活的数据交换格式。
反序列化则是将二进制数据转化为对应的数据结构,方便在Redis内部进行存储和查询等操作。这样可以实现对数据的读取和写入。
Redis支持多种数据结构的序列化和反序列化,包括string、hash、list、set、zset。
SpringBoot提供了多种Redis序列化方式,包括JDK序列化、JSON序列化、FastJSON序列化、Jackson序列化、Protobuf序列化等。其中JDK序列化是默认的序列化方式。
常见的序列化器
- StringRedisSerializer:用于字符串的序列化和反序列化。适用于简单的字符串键值对。
- Jackson2JsonRedisSerializer:使用 Jackson 库进行 JSON 序列化和反序列化。适用于复杂对象的序列化。
- GenericJackson2JsonRedisSerializer:类似于 Jackson2JsonRedisSerializer,但可以处理泛型对象。
- OxmMarshaler:使用 Spring 的 Object-XML 映射功能进行序列化和反序列化。适用于 XML 数据。
- GenericToStringSerializer:将对象转换为字符串,适用于简单的对象。
A服务
使用了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服务
此服务为c++端,使用默认String,该端不做调整的话,修复A端为new StringRedisSerializer()方式
测试
图片
使用StringRedisSerializer来序列化key和value,这个序列化器会把Java字符串直接转换为Redis存储的字节序列,而不添加任何额外的格式化或引号。
使用Jackson2JsonRedisSerializer来序列化key和value,会把Java对象序列化为JSON格式的字符串。如果你序列化的是Java字符串,那么它就会被JSON格式化,并在最终存储在Redis中时带有双引号。