SpringMVC使用Redis的get方法产生反序列化的异常(已解决))

RedisTemplate的get方法的反序列化的异常处理


一、背景

使用redis的哈希表实现投票功能的统计,在get数据时,产生了反序列化的问题。

产生异常的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// get the number of praise and oppose and abandon of vote
public Map<String, Object> statistic_vote(String pid){
HashOperations<String,String,Object> votes_redis = redisTemplate.opsForHash();
Map<String, Object> result = new HashMap<>();
try{
result.put("praise",votes_redis.get(pid,"praise"));
result.put("oppose",votes_redis.get(pid,"oppose"));
result.put("abandon",votes_redis.get(pid,"abandon"));
return result;
}
catch (Exception e){
e.printStackTrace();
return null;
}
}

错误:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
`org.springframework.data.redis.serializer.SerializationException: Cannot deserialize; nested exception is org.springframework.core.serializer.support.SerializationFailedException: Failed to deserialize payload. Is the byte array a result of corresponding serialization for DefaultDeserializer?; nested exception is java.io.EOFException
at org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.deserialize(JdkSerializationRedisSerializer.java:84)
at org.springframework.data.redis.core.AbstractOperations.deserializeHashValue(AbstractOperations.java:354)
at org.springframework.data.redis.core.DefaultHashOperations.get(DefaultHashOperations.java:55)
at com.syz.util.RedisImpl.statistic_vote(RedisImpl.java:88)
at com.syz.controller.MainsiteController.vote_result(MainsiteController.java:139)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:879)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
`

根据异常,可以初步判断是由于spring使用了默认的DefaultDeserializer反序列化器,也就是使用了org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.deserialize这个反序列器,产生了异常,使得序列化和反序列化的方法不一致。


解决方法:

在redis的xml配置文件中增加如下的序列化器

1
2
3
4
5
6
7
8
9
10
11
<context:property-placeholder location="classpath:redis.properties" />
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="jedisConnFactory" />
<!--序列化,不然报ERR hash value is not an integer;错,不能使用increment-->
<property name="keySerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
</property>
<property name="valueSerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
</property>
</bean>

增加了之后,重启服务器运行,仍产报反序列化的异常,可是我上面明明改了呀。经过仔细的检查代码,发现我是用的是散列表存储,而不是简单的key-value键值对,哎哟,简单的key-value满足不了散列表,因此我们还得添加针对hash表的序列化器的配置。

1
2
3
4
5
6
7
8

<property name="hashKeySerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
</property>
<property name="hashValueSerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
</property>

增加hashKey的序列化器,重启服务器后,运行正常~

redis正确截图

如果正常的话,显示在redis中的将是正常的编码,否则序列化不对就会产生奇怪的符号。


总结:

1、稍微总结一下,对于序列化和反序列化,一定要保证我用什么类型序列化,我就要用相对应的类型反序列化,不然类型不对,就会报错。

2、对于redis中increment的方法,获取其值时,它没有被反序列化,因此不会报错,但是使用get方法,获取值时,就需要反序列化了,不然就会报错。

3、对于put,get方法,键值对都要为String的类型,如果直接put的值为整型的话,会出现Long无法转换成String的异常。

4、要对键和值都进行序列化,这样才能获得正确的数据