快捷搜索:  汽车  科技

redis 字节转int(Redis-存Long取Integer类型转换错误)

redis 字节转int(Redis-存Long取Integer类型转换错误)1. 在代码的最外层获取redis中key对应的value值为什么类型会变为Integer呢?跟我一起追踪源码,便会发现问题。@Configuration @AutoConfigureAfter(RedisAutoConfiguration.class) public class RedisConfiguration { @Bean public RedisTemplate<String Object> redisTemplate(JedisConnectionFactory redisConnectionFactory) { RedisTemplate<String Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setCon

背景

最近遇到了两个Redis相关的问题,趁着清明假期,梳理整理。

1.存入Long类型对象,在代码中使用Long类型接收,结果报类型转换错误。

2.String对象的反序列化问题,直接在Redis服务器上新增一个key-value,而后在代码中get(key)时,报反序列化失败。

关于Long类型转换错误Redis的配置如下

Redis中序列化相关的配置,我这里采用的是GenericJackson2JsonRedisSerializer类型的序列化方式(这种方式会有一个类型转换的坑,下面会提到)

@Configuration @AutoConfigureAfter(RedisAutoConfiguration.class) public class RedisConfiguration { @Bean public RedisTemplate<String Object> redisTemplate(JedisConnectionFactory redisConnectionFactory) { RedisTemplate<String Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory); redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer()); redisTemplate.setHashKeySerializer(new StringRedisSerializer()); redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer()); redisTemplate.afterPropertiesSet(); return redisTemplate; } }  

redis 字节转int(Redis-存Long取Integer类型转换错误)(1)

存入Long对象取出Integer对象

测试方法如下

@Test public void redisSerializerLong(){ try { Long longValue = 123L; redisLongCache.set("cacheLongValue" longValue); Object cacheValue = redisLongCache.get("cacheLongValue"); Long a = (Long) cacheValue; }catch (ClassCastException e){ e.printStackTrace(); } }

redis 字节转int(Redis-存Long取Integer类型转换错误)(2)

redis 字节转int(Redis-存Long取Integer类型转换错误)(3)

redis 字节转int(Redis-存Long取Integer类型转换错误)(4)

会报类型转换错误java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Long。

为什么类型会变为Integer呢?跟我一起追踪源码,便会发现问题。

1. 在代码的最外层获取redis中key对应的value值

redisTemplate.opsForValue().get(key);

redis 字节转int(Redis-存Long取Integer类型转换错误)(5)

2.在DefaultValueOperations类中的get(Object key)方法

public V get(Object key) { return execute(new ValueDeserializingRedisCallback(key) { @Override protected byte[] inRedis(byte[] rawKey RedisConnection connection) { return connection.get(rawKey); } } true); }

redis 字节转int(Redis-存Long取Integer类型转换错误)(6)

3.打断点继续往里跟,RedisTemplate中的execute(RedisCallback<T> action boolean exposeConnection boolean pipeline)方法里面,有一行关键代码。

T result = action.doInRedis(connToExpose);

redis 字节转int(Redis-存Long取Integer类型转换错误)(7)

此为获取redis中对应的value值,并对其进行反序列化操作。

4.在抽象类AbstractOperations<K V>中,定义了反序列化操作,对查询结果result进行反序列化。

public final V doInRedis(RedisConnection connection) { byte[] result = inRedis(rawKey(key) connection); return deserializeValue(result); }

redis 字节转int(Redis-存Long取Integer类型转换错误)(8)

V deserializeValue(byte[] value)反序列化

V deserializeValue(byte[] value) { if (valueSerializer() == null) { return (V) value; } return (V) valueSerializer().deserialize(value); }

redis 字节转int(Redis-存Long取Integer类型转换错误)(9)

5.终于到了具体实现类GenericJackson2JsonRedisSerializer

public Object deserialize(@Nullable byte[] source) throws SerializationException { return deserialize(source Object.class); }

redis 字节转int(Redis-存Long取Integer类型转换错误)(10)

实现反序列化方法,注意!这里统一将结果反序列化为Object类型,所以这里便是问题的根源所在,对于数值类型,取出后统一转为Object 导致泛型类型丢失,数值自动转为了Integer类型也就不奇怪了。

public <T> T deserialize(@Nullable byte[] source Class<T> type) throws SerializationException { Assert.notNull(type "Deserialization type must not be null! Pleaes provide Object.class to make use of Jackson2 default typing."); if (SerializationUtils.isEmpty(source)) { return null; } try { return mapper.readValue(source type); } catch (Exception ex) { throw new SerializationException("Could not read JSON: " ex.getMessage() ex); } }  

redis 字节转int(Redis-存Long取Integer类型转换错误)(11)

String对象转义问题

测试方法

@Test public void redisSerializerString() { try { String stringValue = "abc"; redisStringCache.set("codeStringValue" stringValue); String cacheValue = redisStringCache.get("codeStringValue");      // 序列化失败 String serverInsert = redisStringCache.get("serverInsertValue"); if (Objects.equals(cacheValue serverInsert)) { System.out.println("serializer ok"); } else { System.out.println("serializer err"); } } catch (Exception e) { e.printStackTrace(); } }

提前在redis服务器上插入一个非Json格式的String对象

redis 字节转int(Redis-存Long取Integer类型转换错误)(12)

redis 字节转int(Redis-存Long取Integer类型转换错误)(13)

直接在Redis服务器上使用set命令新增一对Key-Value,在代码中取出会反序列化失败,

org.springframework.data.redis.serializer.SerializationException: Could not read JSON: Unrecognized token 'abc': was expecting ('true' 'false' or 'null') at [Source: (byte[])"abc"; line: 1 column: 7]; nested exception is com.fasterxml.jackson.core.JsonParseException: Unrecognized token 'abc': was expecting ('true' 'false' or 'null') at [Source: (byte[])"abc"; line: 1 column: 7] at org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer.deserialize(GenericJackson2JsonRedisSerializer.java:132) at org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer.deserialize(GenericJackson2JsonRedisSerializer.java:110) at org.springframework.data.redis.core.AbstractOperations.deserializeValue(AbstractOperations.java:334) at org.springframework.data.redis.core.AbstractOperations$ValueDeserializingRedisCallback.doInRedis(AbstractOperations.java:60) at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:224) at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:184) at org.springframework.data.redis.core.AbstractOperations.execute(AbstractOperations.java:95) at org.springframework.data.redis.core.DefaultValueOperations.get(DefaultValueOperations.java:48)  

redis 字节转int(Redis-存Long取Integer类型转换错误)(14)

小总结

这个问题是因为,自己在测试的过程中,没有按照代码流程执行,想当然地认为,代码跑出来的结果和自己手动插入的结果是一样的。

在相关的测试验证过程中应该严格的控制变量,不能凭借下意识的决断来操作,谨记软件之事——必作于细!

我是「翎野君」,感谢各位朋友的:点赞收藏评论,我们下期见。 ​

猜您喜欢: