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的時候,會出現錯誤。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM