RedisTemplate的key默認序列化器問題


原文:https://blog.csdn.net/skymouse2002/article/details/80736577

 

redis的客戶端換成了spring-boot-starter-data-redis,碰到了一個奇怪的問題,

在同一個方法中

1.先hset,再hget,正常獲得數據。

在不同的方法中 先hset,再hget獲取不到數據,通過redis的monitor監控發現了命令的問題:

 

實際我的key為JK_HASH:csrk,hashkey為user,但是根據上圖所示,實際執行的命令多了好多其他字符,這是什么原因呢?

在服務器端先確認發現實際有這個Hash,通過hset可以得到正確的數據,所以第一次執行hset的時候命令是正常的,問題可能出現在hget上面,先打開源碼看一下
 

@SuppressWarnings("unchecked")
    public HV get(K key, Object hashKey) {
        final byte[] rawKey = rawKey(key);
        final byte[] rawHashKey = rawHashKey(hashKey);
 
        byte[] rawHashValue = execute(new RedisCallback<byte[]>() {
 
            public byte[] doInRedis(RedisConnection connection) {
                return connection.hGet(rawKey, rawHashKey);
            }
        }, true);
 
        return (HV) deserializeHashValue(rawHashValue);
    }

從這里可以看到實際上傳給redis的都是byte數據,而byte數組是rawKey和rawHashKey生成的,先看下rawKey方法

@SuppressWarnings("unchecked")
    byte[] rawKey(Object key) {
        Assert.notNull(key, "non null key required");
        if (keySerializer() == null && key instanceof byte[]) {
            return (byte[]) key;
        }
        return keySerializer().serialize(key);
    }

然后進一步跟蹤keySerializer()方法

RedisSerializer keySerializer() {
        return template.getKeySerializer();
    }
public RedisSerializer<?> getKeySerializer() {
        return keySerializer;
    }

最后跟蹤到是RedisTemplate中的屬性keySerializer導致的,而通過打印keySerializer的class發現 默認使用的是org.springframework.data.redis.serializer.JdkSerializationRedisSerializer,但它是如何進行初始化的呢,默認的構造函數中並沒有對該屬性進行初始化。

根據RedisTemplate的類關系發現它是繼承RedisAccessor的,而此類是實現的org.springframework.beans.factory.InitializingBean接口,這個接口有個特性,凡是繼承該接口的類,在初始化bean的時候會執行afterPropertiesSet方法。

而afterPropertiesSet方法中,確實對keySerializer進行了初始化:

public void afterPropertiesSet() {
super.afterPropertiesSet();
boolean defaultUsed = false;
if (defaultSerializer == null) {
defaultSerializer = new JdkSerializationRedisSerializer(
classLoader != null ? classLoader : this.getClass().getClassLoader());
}
if (enableDefaultSerializer) {
if (keySerializer == null) {
keySerializer = defaultSerializer;
defaultUsed = true;
}
if (valueSerializer == null) {
valueSerializer = defaultSerializer;
defaultUsed = true;
}
if (hashKeySerializer == null) {
hashKeySerializer = defaultSerializer;
defaultUsed = true;
}
if (hashValueSerializer == null) {
hashValueSerializer = defaultSerializer;
defaultUsed = true;
}
}
if (enableDefaultSerializer && defaultUsed) {
Assert.notNull(defaultSerializer, "default serializer null and not all serializers initialized");
}


if (scriptExecutor == null) {
this.scriptExecutor = new DefaultScriptExecutor<K>(this);
}
initialized = true;
}

在這里可以看到默認使用的正是org.springframework.data.redis.serializer.JdkSerializationRedisSerializer,而問題正在這里,通過查詢可以發現序列化器有這些,而在這里我們需要使用的是StringRedisSerializer

 

加入如下代碼:

 

@Autowired(required = false)
    public void setRedisTemplate(RedisTemplate redisTemplate) {
        RedisSerializer stringSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringSerializer);
        redisTemplate.setValueSerializer(stringSerializer);
        redisTemplate.setHashKeySerializer(stringSerializer);
        redisTemplate.setHashValueSerializer(stringSerializer);
        this.redisTemplate = redisTemplate;
    }
 

 


免責聲明!

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



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