問題描述:
使用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