Redis反序列化异常处理方法

文章目录

    • 问题背景
    • 问题分析
    • 解决方案

问题背景

通过String类型存储,只不过Value是一个自定义对象。暂且叫这个类型为UserBo吧。
当我们通过redisTemplate.opsForValue().set(userId, userBo, 24, TimeUnit.HOURS)存入时并没有什么问题。
可是如果我们通过UserBo userBoCache = (UserBo)redisTemplate.opsForValue().get(userId);方式查看时日志中则会出现报错

Could not read JSON: Could not resolve type id 'com.dps.bo.user.UserBo' as a subtype of `java.lang.Object`

显然对于一个系统而言这是不稳定的。

问题分析

结合报错内容和我们所进行的redis操作可以判断,此问题的原因是我们存入的Value在取出时并不能被转换为UserBo类型的对象。我们暂且称这为反序列化问题。为什么会反序列化失败,原因大抵是我们选用了String类型来存储Object,所以在get时得到的是单纯的String类型,即便打印出来也是UserBo类型对象结构,但仍不能进行强制转换

解决方案

方案一修改spring-data-redis中RedisTemplate默认序列化方式
SpringBoot使用spring-data-redis,RedisTemplate默认的序列化方式是用org.springframework.data.redis.serializer.JdkSerializationRedisSerializer这个类来做序列化,而Redis有自己的序列化方式,所以冲突了 报出了上面的序列化异常的信息。

// 源码参考:spring-data-redis-2.7.2依赖中部分代码
private @Nullable RedisSerializer<?> defaultSerializer;if (defaultSerializer == null) {defaultSerializer = new JdkSerializationRedisSerializer(classLoader != null ? classLoader : this.getClass().getClassLoader());
}

我们可以在使用到redisTemplate的类中加入下面的配置,指定使用的序列化方式,
将key序列化方式改为 StringRedisSerializer,将value序列化方式改为 GenericJackson2JsonRedisSerializer(Jackson2JsonRedisSerializer可以序列化成功,但是反序列化会失败,用GenericJackson2JsonRedisSerializer即可序列化也可反序列化) 。以下两种写法均可——一种是直接更改,一种是配置更改,没什么区别

    private RedisTemplate<String, QuestionTemplate> redisTemplate;//指定用redis的序列化方式进行序列化@Autowired(required = false)public void setRedisTemplate(RedisTemplate redisTemplate) {RedisSerializer stringSerializer = new StringRedisSerializer();//序列化为String//不能反序列化//Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);//序列化为JsonGenericJackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer();redisTemplate.setKeySerializer(stringSerializer);redisTemplate.setValueSerializer(serializer);redisTemplate.setHashKeySerializer(stringSerializer);redisTemplate.setHashValueSerializer(serializer);this.redisTemplate = redisTemplate;}
@Configuration
public class RedisConfig {public RedisConfig() {}@Beanpublic RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {RedisTemplate<Object, Object> redisTemplate = new RedisTemplate();redisTemplate.setConnectionFactory(connectionFactory);Jackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer(Object.class);ObjectMapper om = new ObjectMapper();om.setVisibility(PropertyAccessor.ALL, Visibility.ANY);om.enableDefaultTyping(DefaultTyping.NON_FINAL);serializer.setObjectMapper(om);redisTemplate.setKeySerializer(new StringRedisSerializer());redisTemplate.setValueSerializer(serializer);redisTemplate.setHashKeySerializer(new StringRedisSerializer());redisTemplate.setHashValueSerializer(serializer);return redisTemplate;}
}

PS:适应场景——有系统框架封装的Redis工具,且<String: Object>的String类型存取场景是使用的框架Redis工具 或者 系统框架中有RedisTemplate配置类(说白了就是统一配置到处使用。总不能你在哪个业务类里导入了个RedisTemplate你就得在这个业务类下面手动设置key和Value的序列化方式吧)

方案二自定义Object<->String的序列化与反序列化
UserBo在存入前通过Json工具序列化为String,取出后再通过序列化工具get为UserBo

redisTemplate.opsForValue().set(userId, JSON.toJSONString(userBo), 24, TimeUnit.HOURS);
UserBo userBoCache = JSON.parseObject(redisTemplate.opsForValue().get(userId), UserBo.class);

PS:适应场景——<String: Object>的String类型存取场景不多的情况(毕竟每个都这么写也挺烦的)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/233452.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

webpack知识点总结(基础应用篇)

一、为什么需要webpack 1.为什么使用webpack ①传统的书写方式&#xff0c;加载太多脚本会导致网络瓶颈&#xff0c;如不小心改变JavaScript文件加载顺序&#xff0c;项目会崩溃&#xff0c;还会导致作用域问题、js文件太大无法做到按需加载、可读性和可维护性太低的问题。 ②…

Vue+ElementUI前端添加展开收起搜索框按钮

1、搜索框添加判断 v-if"advanced" <el-form-item label"创建日期" v-if"advanced"><el-date-pickerv-model"daterangeLedat"size"small"style"width: 240px"value-format"yyyy-MM-dd"type&q…

深入了解常见的应用层网络协议

目录 1. HTTP协议 1.1. 工作原理 1.2. 应用场景 1.3. 安全性考虑 2. SMTP协议 2.1. 工作原理 2.2. 应用场景 2.3. 安全性考虑 3. FTP协议 3.1. 工作原理 3.2. 应用场景 3.3. 安全性考虑 4. DNS协议 4.1. 工作原理 4.2. 应用场景 4.3. 安全性考虑 5. 安全性考虑…

scrapy的入门和使用

scrapy的入门使用 学习目标&#xff1a; 掌握 scrapy的安装应用 创建scrapy的项目应用 创建scrapy爬虫应用 运行scrapy爬虫应用 scrapy定位以及提取数据或属性值的方法掌握 response响应对象的常用属性 1 安装scrapy 命令:     sudo apt-get install scrapy 或者&#x…

git切换分支时,该分支的修改被带到另一个分支

git切换分支时&#xff0c;该分支的修改被带到另一个分支_git chechout 切换branch 修改会跟随嘛-CSDN博客

持续集成交付CICD:K8S 自动化完成前端项目应用发布与回滚

目录 一、实验 1.环境 2.GitLab新建项目存放K8S部署文件 3.Jenkins手动测试前端项目CD 流水线代码&#xff08;下载部署文件&#xff09; 4. 将K8S master节点配置为jenkins从节点 5.K8S 手动回滚前端项目版本 6.Jenkins手动测试前端项目CD 流水线代码&#xff08;发布应…

C++学习笔记(十六)

一、多态 1. 多态的基本概念 多态是C面向对象三大特性之一 多态分为两类 1. 静态多态&#xff1a;函数重载 和 运算符重载属于静态多态&#xff0c;复用函数名 2. 动态多态&#xff1a;派生类和虚函数实现运行时多态 静态多态和动态多态区别&#xff1a; 1. 静态多态的函…

Vue Teleport和Vue的介绍

Vue的介绍 Vue是一种用于构建用户界面的渐进式JavaScript框架。它专注于视图层&#xff0c;采用了组件化的开发方式&#xff0c;使得构建复杂的交互界面变得更加简单和高效。Vue具有易上手、灵活、高效、可扩展等特点&#xff0c;因此在开发Web应用程序时非常受欢迎。 下面是…

useConsole的封装,vue,react,htmlscript标签,通用

之前用了接近hack的方式实现了console的封装&#xff0c;目标是获取console.log函数的执行&#xff08;调用栈所在位置&#xff09;所在的代码行数。 例如以下代码&#xff0c;执行window.mylog(1)时候&#xff0c;console.log实际是在匿名的箭头函数()>{//这里执行的} con…

流动的力量:解锁Java 8 Stream的高级特性

前言 随着Java 8的Stream API的引入&#xff0c;编程世界得到了一场深刻的变革。Stream API为我们打开了全新的编码范式&#xff0c;不仅使代码变得更为简洁&#xff0c;同时也提供了一种全新的数据处理方式。在本文中&#xff0c;我们将进一步挖掘Stream的潜力&#xff0c;深…

【IDEA】Intellij IDEA相关配置

IDEA 全称 IntelliJ IDEA&#xff0c;是java编程语言的集成开发环境。IntelliJ在业界被公认为最好的Java开发工具&#xff0c;尤其在智能代码助手、代码自动提示、重构、JavaEE支持、各类版本工具(git、svn等)、JUnit、CVS整合、代码分析、 创新的GUI设计等方面的功能可以说是超…

SpringCloud源码探析(十二)-基于SpringBoot开发自定义中间件

1.概述 中间件是一种介于操作系统和应用软件之间&#xff0c;为应用软件提供服务功能的软件&#xff0c;按功能划分有消息中间件&#xff08;Kafka、RocketMQ&#xff09;、通信中间件&#xff08;RPC通信中间件&#xff0c;dubbo等&#xff09;&#xff0c;应用服务器等。中间…

Java实现一个在windows环境下的文件搜索引擎

以下是一个简单的Java实现的Windows文件搜索引擎的示例代码&#xff1a; import java.io.File; import java.util.ArrayList; import java.util.List;public class FileSearchEngine {public static void main(String[] args) {String searchDirectory "C:/"; // …

tensorflow入门 自定义模型

前面说了自定义的层&#xff0c;接下来自定义模型&#xff0c;我们以下图为例子 这个模型没啥意义&#xff0c;单纯是为了写代码实现这个模型 首先呢&#xff0c;我们看有几个部分&#xff0c;dense不需要我们实现了&#xff0c;我们就实现Res&#xff0c;为了实现那个*3,我们…

WPF——样式和控件模板、数据绑定与校验转换

样式和控件模板 合并资源字典 Style简单样式的定义和使用 ControlTemplate控件模板的定义和使用 定义 使用 Trigger触发器 数据绑定与校验转换 数据绑定的设置 代码层实现绑定

TransXNet实战:使用 TransXNet实现图像分类任务(二)

文章目录 训练部分导入项目使用的库设置随机因子设置全局参数图像预处理与增强读取数据设置Loss设置模型设置优化器和学习率调整策略设置混合精度&#xff0c;DP多卡&#xff0c;EMA定义训练和验证函数训练函数验证函数调用训练和验证方法 运行以及结果查看测试完整的代码 在上…

监控k8s controller和scheduler,创建serviceMonitor以及Rules

目录 一、修改kube-controller和kube-schduler的yaml文件 二、创建service、endpoint、serviceMonitor 三、Prometheus验证 四、创建PrometheusRule资源 五、Prometheus验证 直接上干货 一、修改kube-controller和kube-schduler的yaml文件 注意&#xff1a;修改时要一个节…

HTML CSS 进度条

1 原生HTML标签 <meter>&#xff1a;显示已知范围的标量值或者分数值<progress>&#xff1a;显示一项任务的完成进度&#xff0c;通常情况下&#xff0c;该元素都显示为一个进度条 1.1 <meter> <html><head><style>meter{width:200px;}…

微软官宣放出一个「小模型」,仅2.7B参数,击败Llama2和Gemini Nano 2

就在前一阵谷歌深夜炸弹直接对标 GPT-4 放出 Gemini 之后&#xff0c;微软这两天也紧锣密鼓进行了一系列动作。尽管时间日趋圣诞假期&#xff0c;但是两家巨头硬碰硬的军备竞赛丝毫没有停止的意思。 就在昨日&#xff0c;微软官宣放出一个“小模型” Phi-2&#xff0c;这个 Ph…

vim 基本命令查找和替换

vim简单的命令用着还好。比如插入&#xff0c;删除&#xff0c;查询。但替换就用的比较少。所以&#xff0c;还是需要用的时候拿出来对照者看。 使用vim编辑文件&#xff1a; vim xxx 复制 进入之后的界面叫做命令模式界面。可以修改文件编辑的时候叫做插入模式。 (命令模…