谈谈spring-data-redis遇到的问题

来源:互联网 发布:淘宝详情图怎么加链接 编辑:程序博客网 时间:2024/06/08 00:06

谈谈spring-data-redis遇到的问题

1. key序列化问题

使用spring-data-redis中的redisTemplate存储key-value,然后使用redis-cli去查询时查询不到相应的key。使用keys *时发现redis中key的前缀多了一些字符

\xac\xed\x00\x05t\x00\x0e

问题关键

使用spring-data-redis,默认情况下使用的是org.springframework.data.redis.serializer.JdkSerializationRedisSerializer来进行序列化key

我们看看关键代码 RedisTemplate

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;    }

解决问题

手动设置key的序列化方式为StringRedisSerializer

看代码

@Beanpublic RedisTemplate<String, ?> redisTemplate(RedisConnectionFactory factory) {    RedisTemplate<String, Object> redisTemplate = new RedisTemplate();    redisTemplate.setConnectionFactory(factory);    RedisSerializer<String> stringRedisSerializer = new StringRedisSerializer();    redisTemplate.setKeySerializer(stringRedisSerializer);    redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());    return redisTemplate;}

2. value 序列化问题

我们在使用无参构造GenericJackson2JsonRedisSerializer序列化对象时,序列化出来的值是这样的

{  "@class": "com.xxx.MenuTask",  "taskId": "1617776640",  "planId": "10000000",  "createTime": [    "java.util.Date",    1500540438240  ],  "execDate": [    "java.util.Date",    1500480000000  ],  "status": 0,  "totals": {    "@class": "java.util.HashMap",    "35430d2a56ae508f24a76a68e71b9f53": 1500,    "75aa86c5a85f65687c95444655c51de9": 500,    "ab90efa7a0079b88f224a296b211c209": 1000  }}

这样的json格式使用其他的json序列化时会出现无法解析的错误,如fastjson解析时会抛出异常

com.alibaba.fastjson.JSONException: parse error    at com.alibaba.fastjson.serializer.DateCodec.cast(DateCodec.java:206)    at com.alibaba.fastjson.parser.deserializer.AbstractDateDeserializer.deserialze(AbstractDateDeserializer.java:142)    at com.alibaba.fastjson.parser.deserializer.AbstractDateDeserializer.deserialze(AbstractDateDeserializer.java:19)    at com.alibaba.fastjson.parser.deserializer.DefaultFieldDeserializer.parseField(DefaultFieldDeserializer.java:71)    at com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer.parseField(JavaBeanDeserializer.java:790)    at com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer.deserialze(JavaBeanDeserializer.java:595)

主要原因是因为Date格式不正确,应该是一个long类型的数字,而不是一个数组

问题关键

我们来分析一下源码

public class GenericJackson2JsonRedisSerializer implements RedisSerializer<Object> {    private final ObjectMapper mapper;    /**     * Creates {@link GenericJackson2JsonRedisSerializer} and configures {@link ObjectMapper} for default typing.     */    public GenericJackson2JsonRedisSerializer() {        this((String) null);    }    public GenericJackson2JsonRedisSerializer(String classPropertyTypeName) {        this(new ObjectMapper());//------------------------ start ------------------------        mapper.registerModule(new SimpleModule().addSerializer(new NullValueSerializer(classPropertyTypeName)));        if (StringUtils.hasText(classPropertyTypeName)) {            mapper.enableDefaultTypingAsProperty(DefaultTyping.NON_FINAL, classPropertyTypeName);        } else {            mapper.enableDefaultTyping(DefaultTyping.NON_FINAL, As.PROPERTY);        }//------------------------ end ------------------------    }    public GenericJackson2JsonRedisSerializer(ObjectMapper mapper) {        Assert.notNull(mapper, "ObjectMapper must not be null!");        this.mapper = mapper;    }    ...    ...}

原因所在地方 // — start — // — end —之间的那段代码 源码的63-69行,这里会将属性的类型写到json中。

解决问题

手动设置一个ObjectMapper,这样redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer(new ObjectMapper()));

@Beanpublic RedisTemplate<String, ?> redisTemplate(RedisConnectionFactory factory) {    RedisTemplate<String, Object> redisTemplate = new RedisTemplate();    redisTemplate.setConnectionFactory(factory);    RedisSerializer<String> stringRedisSerializer = new StringRedisSerializer();    redisTemplate.setKeySerializer(stringRedisSerializer);    redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer(new ObjectMapper()));    return redisTemplate;}
原创粉丝点击