使用spring-redis-data 的hIncrBy增加值后,用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.StreamCorruptedException: invalid stream header: 31332E35
at org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.deserialize(JdkSerializationRedisSerializer.java:41)
at org.springframework.data.redis.core.AbstractOperations.deserializeHashValue(AbstractOperations.java:316)
at org.springframework.data.redis.core.DefaultHashOperations.get(DefaultHashOperations.java:55)
at com.yss.sofa.whale.cache.codis.client.CodisHashClient.getValue(CodisHashClient.java:103)
at com.yss.sofa.whale.cache.redis.client.junit.client.CodisHashClientTest.incrbyDouble(CodisHashClientTest.java:80)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
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.StreamCorruptedException: invalid stream header: 31332E35
at org.springframework.core.serializer.support.DeserializingConverter.convert(DeserializingConverter.java:64)
at org.springframework.core.serializer.support.DeserializingConverter.convert(DeserializingConverter.java:34)
at org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.deserialize(JdkSerializationRedisSerializer.java:39)
... 29 more
Caused by: java.io.StreamCorruptedException: invalid stream header: 31332E35
at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:804)
at java.io.ObjectInputStream.<init>(ObjectInputStream.java:299)
at org.springframework.core.serializer.DefaultDeserializer.deserialize(DefaultDeserializer.java:39)
at org.springframework.core.serializer.support.DeserializingConverter.convert(DeserializingConverter.java:59)
... 31 more
跟代码发现:
JedisConnection里:
public Double hIncrBy(byte[] key, byte[] field, double delta) {
try {
if (isPipelined()) {
pipeline(new JedisResult(pipeline.hincrByFloat(key, field, delta)));
return null;
}
if (isQueueing()) {
transaction(new JedisResult(transaction.hincrByFloat(key, field, delta)));
return null;
}
return jedis.hincrByFloat(key, field, delta);
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
BinaryJedis:
public Double hincrByFloat(final byte[] key, final byte[] field, final double value) {
checkIsInMultiOrPipeline();
client.hincrByFloat(key, field, value);
final String dval = client.getBulkReply();
return (dval != null ? new Double(dval) : null);
}
BinaryClient:
public void hincrByFloat(final byte[] key, final byte[] field, double increment) { sendCommand(HINCRBYFLOAT, key, field, toByteArray(increment)); } ... public static final byte[] toByteArray(final double value) { return SafeEncoder.encode(String.valueOf(value)); }
SafeEncoder:
public static byte[] encode(final String str) {
try {
if (str == null) {
throw new JedisDataException("value sent to redis cannot be null");
}
return str.getBytes(Protocol.CHARSET);
} catch (UnsupportedEncodingException e) {
throw new JedisException(e);
}
}
此处输入的值double 是按string的方式进行序列化的并存入缓存的。
下面再看从缓存中取值的过程 :
DefaultHashOperations:
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); } ... <HV> HV deserializeHashValue(byte[] value) { if (hashValueSerializer() == null) { return (HV) value; } return (HV) hashValueSerializer().deserialize(value); }
可以看出取值后的反序列化是按照配置文件里配置的hashValueSerializer()序列化方式进行反序列化的,如果hashValueSerializer()配置的是JdkSerializationRedisSerializer,就会报上述的错误。
解决办法:
在取值时把序列化方法设为stringSerializer,取后再恢复。
public Object getValue(Object key, Object field) { RedisSerializer<?> hValueSerializer= template.getHashValueSerializer(); template.setHashValueSerializer(stringSerializer); Object value = operations.get(key, field); ... template.setHashValueSerializer(hValueSerializer); return value; }