背景

最近遇到了两个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;
}
}  

存入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();
}
}

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

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

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

redisTemplate.opsForValue().get(key);

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);
}

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

T result = action.doInRedis(connToExpose); 

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

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

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

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

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

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

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

实现反序列化方法,注意!这里统一将结果反序列化为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);
}
}  

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服务器上使用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)  

小总结

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

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

参考资料:

https://blog.csdn.net/f641385712/article/details/84679456

关于Redis-存Long取Integer类型转换错误的问题;String对象被转义的问题的更多相关文章

  1. springboot:redis反序列化发生类型转换错误

    明明是同一个类,在反序列时报类型转换错误,真实奇怪.经查找资料,说是引入了devtools的缘故. 注释掉以下内容: <dependency> <groupId>org.spr ...

  2. spring参数类型异常输出(二), SpringMvc参数类型转换错误输出(二)

    spring参数类型异常输出(二), SpringMvc参数类型转换错误输出(二) >>>>>>>>>>>>>>&g ...

  3. Struts(十九):类型转换、类型转换错误消息及显示

    类型转换概念 1.从html表单页面到一个Action对象,类型转化是从字符串到一个非字符串:html并没有“类型”的概念,每个表单输入的信息都只可能是一个字符串或者一个字符串数组,但是在服务器端,必 ...

  4. $Django 路飞之显示视频,Redis存购物车数据,优惠卷生成表,优惠卷的一个领取表。(知识小回顾)

    知识小回顾之json序列化问题 精髓:支持python的几种数据类型(注意不是对象,不能放对象),其次是tuple变list. ensure_ascii:默认值True,如果dict内含有non-AS ...

  5. 关于integer overflow错误

    前端突然报了integer overflow错误,int类型溢出也就是数字超过了int类型,一看很懵逼,查看后台日期发现是在Math.toIntExact()方法报错 那么我们看下方法内部代码: /* ...

  6. SpringMVC 类型转换错误自定义返回

    在SpringMVC捕获异常只需要实现接口org.springframework.web.servlet.HandlerExceptionResolver,即可自定义返回异常,如:属性转换异常 @Re ...

  7. redis存json数据时选择string还是hash

    redis存json数据时选择string还是hash 我们在缓存json数据到redis时经常会面临是选择string类型还是选择hash类型去存储.接下来我从占用空间和IO两方面来分析这两种类型的 ...

  8. 《javascript》高级程序设计——类型转换错误

    容易发生类型转换错误的另一个地方,就是流控制语句.像if之类的语句在确定下一步操作之前,会自动把任何值转换成布尔值.尤其是if语句,如果使用不当,最容易出错.来看下面的例子. function con ...

  9. [原创]java WEB学习笔记67:Struts2 学习之路-- 类型转换概述, 类型转换错误修改,如何自定义类型转换器

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

随机推荐

  1. laravel 查看sql

    方法一: 我们有时候想测试一段代码生产的 SQL 语句,比如: 我们想看 App\User::all(); 产生的 SQL 语句,我们简单在 routes.php 做个实验即可: //app/Http ...

  2. 单例模式全面学习(C++版)

    单例模式:用来创建独一无二的,只能够有一个实例的对象. 单例模式的结构是设计模式中最简单的,但是想要完全实现一个线程安全的单例模式还是有很多陷阱的,所以面试的时候属于一个常见的考点~ 单例模式的应用场 ...

  3. 【题目】求n以内的素数个数

    最近在leetCode上刷提,还是满锻炼人的,为以后面试打基础吧.不多说下面开始. 问题:求[2,n]之间的素数的个数. 来源:leetCode OJ 提示: Let's start with a i ...

  4. 【BZOJ2658】[Zjoi2012]小蓝的好友(mrx) 平衡树维护笛卡尔树+扫描线

    [BZOJ2658][Zjoi2012]小蓝的好友(mrx) Description 终于到达了这次选拔赛的最后一题,想必你已经厌倦了小蓝和小白的故事,为了回馈各位比赛选手,此题的主角是贯穿这次比赛的 ...

  5. 【CF903G】Yet Another Maxflow Problem 线段树

    [CF903G]Yet Another Maxflow Problem 题意:一张图分为两部分,左边有n个点A,右边有m个点B,所有Ai->Ai+1有边,所有Bi->Bi+1有边,某些Ai ...

  6. 使用COSBench工具对ceph s3接口进行压力测试--续

    之前写的使用COSBench工具对ceph s3接口进行压力测试是入门,在实际使用是,配置内容各不一样,下面列出 压力脚本是xml格式的,套用UserGuide文档说明,如下 有很多模板的例子,在co ...

  7. Unity3D笔记 切水果二 刀光剑影

    一.步骤一创建一个空GameObject.js 二.代码 #pragma strict var myColor:Color; var firstPosition:Vector3;//鼠标点击的第一个点 ...

  8. AngularJS初始(一)

    什么是AngularJs? angularjs是一个为动态WEB应用设计的结构框架.它能让你使用HTML作为模板语言,通过扩展HTML的语法,让你能更清楚.简洁地构建你的应用组件.它的创新点在于,利用 ...

  9. 一个js文件如何加载另外一个js文件

    方法一,在调用文件的顶部加入下例代码: document.write(”<script language=javascript src=’/js/import.js’></scrip ...

  10. django和flask的区别

    转载至https://blog.csdn.net/tulan_xiaoxin/article/details/79132214 (1)Flask Flask确实很“轻”,不愧是Micro Framew ...