RedisTemplate SerializationFailedException: Failed to deserialize payload 异常解决

问题描述:

   使用RedisTemplate(spring-data-redis )进行redis操作的封装 , 现有一个incr的key , 当调用incr后返回值一切正常, 当对此key进行get调用的时候出现了如下的异常:

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:42)  
    at org.springframework.data.redis.core.AbstractOperations.deserializeValue(AbstractOperations.java:274)  
    at org.springframework.data.redis.core.AbstractOperations$ValueDeserializingRedisCallback.doInRedis(AbstractOperations.java:52)  
    at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:185)  
    at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:153)  
    at org.springframework.data.redis.core.AbstractOperations.execute(AbstractOperations.java:86)  
    at org.springframework.data.redis.core.DefaultValueOperations.get(DefaultValueOperations.java:43)  
    at org.springframework.data.redis.core.DefaultBoundValueOperations.get(DefaultBoundValueOperations.java:42)  
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)  
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)  
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)  
    at java.lang.reflect.Method.invoke(Unknown Source)  
    at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:176)  
    at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:436)  
    at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:424)  
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:900)  
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:827)  
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)  
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:778)  
      
Caused by: 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.core.serializer.support.DeserializingConverter.convert(DeserializingConverter.java:61)  
    at org.springframework.core.serializer.support.DeserializingConverter.convert(DeserializingConverter.java:1)  
    at org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.deserialize(JdkSerializationRedisSerializer.java:40)  
    ... 38 more  
Caused by: java.io.EOFException  
    at java.io.ObjectInputStream$PeekInputStream.readFully(Unknown Source)  
    at java.io.ObjectInputStream$BlockDataInputStream.readShort(Unknown Source)  
    at java.io.ObjectInputStream.readStreamHeader(Unknown Source)  
    at java.io.ObjectInputStream.<init>(Unknown Source)  
    at org.springframework.core.serializer.DefaultDeserializer.deserialize(DefaultDeserializer.java:38)  
    at org.springframework.core.serializer.support.DeserializingConverter.convert(DeserializingConverter.java:58)  
    ... 40 more

 可以看出是sping对redis查询的返回结果进行deserialize的时候出错了 , 当然异常的提示也很明确:序列号对象生成这个字节数组的方法是否与默认的反序列化方法相对应;应该就是对称性吧 , 你用A方法对B进行序列号然后用不对称的反序列化方法C进行反序列号 , 肯定会有问题

简单来说调用incr后得到 值不会出错是没有经过redistemplate的deserialize, 而get必须经过 , 所以只要设置redistemplate的ValueSerializer即可:

redisTemplate.setValueSerializer(new GenericToStringSerializer<Long>(Long.class));

最好的处理办法是只需要配置RedisTemplate的几个属性就可以了

给value加入序列化

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

贴出我的代码

    <!-- 
        其中order属性代表其加载顺序,
        而ignoreUnresolvablePlaceholders为是否忽略不可解析的 Placeholder,
        如配置了多个PropertyPlaceholderConfigurer,则需设置为true
        其中classpath是引用src目录下的文件写法。
         -->
    <bean id="propertyConfigurerRedis" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">  
        <property name="order" value="1" />  
        <property name="ignoreUnresolvablePlaceholders" value="true" />  
        <property name="locations">  
            <list>  
                <value>classpath:redis.properties</value>  
            </list>  
        </property>  
    </bean>  
    
    <!-- 单个redis配置 -->
     <!-- redis连接池的配置 -->
    <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
      <property name="maxIdle" value="${redis.maxIdle}"/>
      <property name="minIdle" value="${redis.minIdle}"/>
      <property name="testOnBorrow" value="${redis.testOnBorrow}"/>
      <property name="testOnReturn" value="${redis.testOnReturn}"/>
    </bean>
    <!-- redis的连接池pool,不是必选项:timeout/password  -->
    <bean id = "jedisPool" class="redis.clients.jedis.JedisPool">
      <constructor-arg index="0" ref="jedisPoolConfig"/>
      <constructor-arg index="1" value="${redis.host}"/>
      <constructor-arg index="2" value="${redis.port}" type="int"/> <!-- port-->
      <constructor-arg index="3" value="${redis.timeout}" type="int"/> <!-- timeout -->
      <constructor-arg index="4" value="${redis.password}"/>  <!-- password -->
    </bean>
    
    <!-- 以下是spring-data-redis配置方式 -->
    <bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"  
        p:host-name="${redis.host}" p:port="${redis.port}" p:password="${redis.password}" p:pool-config-ref="jedisPoolConfig"/>  
      
     <!--  SDR默认采用的序列化策略有两种,一种是String的序列化策略,一种是JDK的序列化策略。
        StringRedisTemplate默认采用的是String的序列化策略,保存的key和value都是采用此策略序列化保存的。
        RedisTemplate默认采用的是JDK的序列化策略,保存的key和value都是采用此策略序列化保存的。
        就是因为序列化策略的不同,即使是同一个key用不同的Template去序列化,结果是不同的。所以根据key去删除数据的时候就出现了删除失败的问题。 
     -->
    <!-- redis 序列化策略 ,通常情况下key值采用String序列化策略, -->
    <!-- 如果不指定序列化策略,StringRedisTemplate的key和value都将采用String序列化策略; -->
    <!-- 但是RedisTemplate的key和value都将采用JDK序列化 这样就会出现采用不同template保存的数据不能用同一个template删除的问题 -->
    <bean id="stringRedisSerializer"  class="org.springframework.data.redis.serializer.StringRedisSerializer" />
    <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
        <property name="connectionFactory" ref="connectionFactory" /> 
        <property name="keySerializer" ref="stringRedisSerializer" />
        <property name="hashKeySerializer" ref="stringRedisSerializer" />
        <property name="valueSerializer" ref="stringRedisSerializer"/>
    </bean>
    

redis.properties

#IP  
redis.host=192.168.1.249
#Port  
redis.port=6379
#password
redis.password=123456
#maxIdle
redis.maxIdle=1000
#minIdle
redis.minIdle=100
#timeout
redis.timeout=2000
原文地址:https://www.cnblogs.com/shihaiming/p/6019795.html