• 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;
        }
     
  • 相关阅读:
    【大数据】HDFS高可用
    【Redis】常用命令、问题排查、内存优化
    【OOM】记一次线上OOM解决全流程
    【Git】Github如何弥补提交记录contributions
    Hash算法与Hash碰撞
    【计算机基础】存储单位换算
    【大数据】技术选型对比
    【MQ】Kafka架构与原理
    【Git】Git常用命令合集
    【maven】基本知识点
  • 原文地址:https://www.cnblogs.com/shihaiming/p/10978065.html
Copyright © 2020-2023  润新知