关于Redis-存Long取Integer类型转换错误的问题;String对象被转义的问题
背景
最近遇到了两个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对象被转义的问题的更多相关文章
- springboot:redis反序列化发生类型转换错误
明明是同一个类,在反序列时报类型转换错误,真实奇怪.经查找资料,说是引入了devtools的缘故. 注释掉以下内容: <dependency> <groupId>org.spr ...
- spring参数类型异常输出(二), SpringMvc参数类型转换错误输出(二)
spring参数类型异常输出(二), SpringMvc参数类型转换错误输出(二) >>>>>>>>>>>>>>&g ...
- Struts(十九):类型转换、类型转换错误消息及显示
类型转换概念 1.从html表单页面到一个Action对象,类型转化是从字符串到一个非字符串:html并没有“类型”的概念,每个表单输入的信息都只可能是一个字符串或者一个字符串数组,但是在服务器端,必 ...
- $Django 路飞之显示视频,Redis存购物车数据,优惠卷生成表,优惠卷的一个领取表。(知识小回顾)
知识小回顾之json序列化问题 精髓:支持python的几种数据类型(注意不是对象,不能放对象),其次是tuple变list. ensure_ascii:默认值True,如果dict内含有non-AS ...
- 关于integer overflow错误
前端突然报了integer overflow错误,int类型溢出也就是数字超过了int类型,一看很懵逼,查看后台日期发现是在Math.toIntExact()方法报错 那么我们看下方法内部代码: /* ...
- SpringMVC 类型转换错误自定义返回
在SpringMVC捕获异常只需要实现接口org.springframework.web.servlet.HandlerExceptionResolver,即可自定义返回异常,如:属性转换异常 @Re ...
- redis存json数据时选择string还是hash
redis存json数据时选择string还是hash 我们在缓存json数据到redis时经常会面临是选择string类型还是选择hash类型去存储.接下来我从占用空间和IO两方面来分析这两种类型的 ...
- 《javascript》高级程序设计——类型转换错误
容易发生类型转换错误的另一个地方,就是流控制语句.像if之类的语句在确定下一步操作之前,会自动把任何值转换成布尔值.尤其是if语句,如果使用不当,最容易出错.来看下面的例子. function con ...
- [原创]java WEB学习笔记67:Struts2 学习之路-- 类型转换概述, 类型转换错误修改,如何自定义类型转换器
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...
随机推荐
- jquery validate使用笔记
1 表单验证的准备工作 在开启长篇大论之前,首先将表单验证的效果展示给大家. 1.点击表单项,显示帮助提示 2.鼠标离开表单项时,开始校验元素 3.鼠标离开后的正确.错误提示及鼠标移入时的帮 ...
- import 与 from…import 的区别
首先你要了解 import 与 from…import 的区别. import 模块:导入一个模块:注:相当于导入的是一个文件夹,是个相对路径. from…import:导入了一个模块中的一个函数:注 ...
- 【转】UTF16和UTF8什么区别?
这是一篇程序员写给程序员的趣味读物.所谓趣味是指可以比较轻松地了解一些原来不清楚的概念,增进知识,类似于打RPG游戏的升级.整理这篇文章的动机是两个问题: 问题一: 使用Windows记事本的“另存为 ...
- C++ Error: error LNK2019: unresolved external symbol
在某工程中新添加了文件x.cu与x.hpp,实现了一些功能,最后编译整个工程的时候就出现了这个问题: error LNK2019: unresolved external symbol 这是链接错误, ...
- iOS - viewDidLoad, viewWillDisappear, viewWillAppear区别及加载顺序
viewWillAppear: Called when the view is about to made visible. Default does nothing视图即将可见时调用.默认情况下不执 ...
- iOS - 使用苹果自带的UIVideoEditController进行视频编辑
UIVideoEditorController类包含了由系统提供的界面,使用户可以交互式的剪切视频.UIVideoEditorController对象处理用户的交互并且提供把编辑后的视频的文件系统路径 ...
- python-django开发学习笔记四
先插入一条广告,博主新开了一家淘宝店,经营自己纯手工做的发饰,新店开业,只为信誉!需要的亲们可以光顾一下!谢谢大家的支持!店名: 小鱼尼莫手工饰品店经营: 发饰.头花.发夹.耳环等(手工制作)网店: ...
- 2018C语言第二次作业
一.学习内容总结 1.指针是一种数据类型,同样占有空间,其存储的是内存地址: 2.定义指针变量要在变量名之前加“*”字符表示: 3.“&”是取地址运算符,“*”是间接运算符: (注:声名和使用 ...
- 2013Top100summit公布重量级演讲嘉宾及大会日程
TOP100SUMMIT对外公布重量级嘉宾及大会日程 第四届技术商业论坛暨全球软件案例研究峰会(TOP100summit)将于11月23-26日北京召开.本届大会以“技术推动商业变革”为主题,力邀业界 ...
- Python中各种括号的区别、用途及使用方法
python语言最常见的括号有三种,分别是:小括号( ).中括号[ ]和大括号也叫做花括号{ }.其作用也各不相同,分别用来代表不同的python基本内置数据类型. python中的小括号( ):代表 ...