• 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序列化来进行操作呢?

    原初始化操作如下:

    @Bean
    public 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;
    }
    

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

    @Bean
    public 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的时候,会出现错误。
  • 相关阅读:
    Java并发编程 LockSupport源码分析
    [No000010F]Git8/9-使用GitHub
    [No000010E]Git7/9-标签管理
    [No000010D]Git6/9-分支管理
    [No000010C]Git5/9-远程仓库
    [No000010B]Git4/9-时光机穿梭
    [No000010A]Git3/9-创建版本库
    [No0000109]Git2/9-安装Git
    [No0000108]Git1/9-Git简介与入门
    [No000011D].NETCORE1/19-.NET Core 指南
  • 原文地址:https://www.cnblogs.com/lifacheng/p/15956918.html
Copyright © 2020-2023  润新知