写点什么

SpringDataRedis 序列化带有双引号

作者:编号94530
  • 2022 年 3 月 02 日
  • 本文字数:2099 字

    阅读完需:约 7 分钟

SpringDataRedis序列化带有双引号

1. 背景

在使用 Spring Data Redis 的 hash 存数据的时发现,如果存值的泛型和取出来的泛型对象不同时,可能存在值不相等。记录下过程与解决方案,避免大家重复踩坑。

2. 问题说明

情况如下,用图说明。


测试代码


2.1 RedisOpts 操作

RedisOpts 是对 RedisTemplate<String,?>进行了一层封装,在用 hash 操作时,存入的 key 是test-hash,value 是RedisUtils.class.getName(), 取值得时候有两种方式,分别是转化成了String.classObject.class

2.1.1 String.class

我们想把结果转化成String.class的时候,RedisOpts 会采用 RedisTemplate<String,String>,发现取出来的值多了一对双引号(""),这也就导致了在执行nameSpaceString.equals(RedisUtils.class.getName()出现了不相等的情况。

2.1.2 Object.class

我们在未对值进行转化,采用 Object.class 的时候,RedisOpts 会采用 RedisTemplate<String,Object>执行nameSpaceObject.equals(RedisUtils.class.getName()出现了相等。

2.2 RedisTemplate<Object,Object> 验证

直接用 RedisTemplate 验证,存相同的值,再取值的时候,直接返回的也是 Object 对象,并且两个值是相等的,并没有多出双引号("")

2.3 解决与思考

取出来的值是 Object 的时候值是相等的,只是值在转化的过程(由Object->String)中出现了双引号,那我们是不是可以在初始化的时候对值自动序列化,而不用采用 SpringDataRedis 的 json 序列化来进行操作呢?


原初始化操作如下:


@Beanpublic RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {  RedisTemplate<Object, Object> template = new RedisTemplate<>();  // jackson自带的序列化方式  GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();  StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();  // key采用字符串序列化  template.setKeySerializer(stringRedisSerializer);  // value序列化  template.setValueSerializer(jackson2JsonRedisSerializer);  // hash key序列化  template.setHashKeySerializer(stringRedisSerializer);  // value  template.setHashValueSerializer(jackson2JsonRedisSerializer);  template.setConnectionFactory(redisConnectionFactory);  template.afterPropertiesSet();  return template;}
复制代码


在经过一番思考后,对值的序列化进行了修改。修改代码如下:


@Beanpublic RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {  RedisTemplate<Object, Object> template = new RedisTemplate<>();  GenericJackson2JsonRedisSerializerCustomized jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializerCustomized();  StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();  template.setKeySerializer(stringRedisSerializer);  template.setValueSerializer(jackson2JsonRedisSerializer);  template.setHashKeySerializer(stringRedisSerializer);  template.setHashValueSerializer(jackson2JsonRedisSerializer);  template.setConnectionFactory(redisConnectionFactory);  template.afterPropertiesSet();  return template;}
复制代码


public class GenericJackson2JsonRedisSerializerCustomized extends GenericJackson2JsonRedisSerializer {    @Override    public byte[] serialize(Object source) throws SerializationException {        if (Objects.nonNull(source)) {            if (source instanceof String || source instanceof Character) {                return source.toString().getBytes();            }        }        return super.serialize(source);    }    @Override    public <T> T deserialize(byte[] source, Class<T> type) throws SerializationException {        return super.deserialize(source, type);    }}
复制代码


当存储的值是字符串的时候,直接采用 jdk 的 getbytes 方法,而不是采用 jackson 的序列化方式。这样就避免在值是 String 类型的时候,被当做对象序列化,存储有双引号。在取出的时候多出双信号了。

2.3.1 采用默认 jackson 序列化值

Jackson默认序列化


我们可以看到,在采用默认 jackson 序列化值的时候,存储的值是带有双引号("")的.

2.3.2 改造后的 jackson 序列化

改造后Jackson序列化


我们在用改造后的 jackson 序列化的时候可以看到,存储的值并没有带上双引号("")。但是在改造后,执行我们的测试代码时,在转化成 Object 出现了问题。如下:


转化Object对象失败


我们可以看到,在 44 行,出现了错误。也就是改造后,如果存储的是 String,但当 Object 获取的时候会报错(对象非 jackson 序列化字符串)。

3. 总结

经过上面的一系列操作,我们得到一个结论,在使用 SpringRedis 存储时,如果采用默认 Jackson 序列化,在存储值的时候会当做 Object 存储,带有双引号。


解决方案有 2 点,


  1. 进行妥协,采用 Object 方式获取,不进行数据转化

  2. 对 jackson 改造,可以直接转化成 string 对象,但是在用 jackson 转成 Object 的时候,会出现错误。

发布于: 刚刚阅读数: 2
用户头像

编号94530

关注

你的每一个点赞,我都当做喜欢 2020.04.29 加入

新时代农民工

评论

发布
暂无评论
SpringDataRedis序列化带有双引号_redis_编号94530_InfoQ写作平台