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有自己的序列化方式,所以冲突了 报出了上面的序列化异常的信息。

java 复制代码
// 源码参考: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即可序列化也可反序列化) 。以下两种写法均可------一种是直接更改,一种是配置更改,没什么区别

java 复制代码
    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);//序列化为Json
        GenericJackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer();
        redisTemplate.setKeySerializer(stringSerializer);
        redisTemplate.setValueSerializer(serializer);
        redisTemplate.setHashKeySerializer(stringSerializer);
        redisTemplate.setHashValueSerializer(serializer);
        this.redisTemplate = redisTemplate;
    }
java 复制代码
@Configuration
public class RedisConfig {
    public RedisConfig() {
    }
    @Bean
    public 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

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

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

相关推荐
wayuncn1 小时前
哈尔滨电商企业服务器托管方案
运维·服务器·数据库
重整旗鼓~2 小时前
27.Redisson基本使用和可重入性
数据库·redis·缓存
瑶总迷弟2 小时前
使用 Docker 和 docker-compose 快速部署 openGauss
linux·数据库·云原生·eureka
C.R.xing2 小时前
Pyspark分布式访问NebulaGraph图数据库
数据库·分布式·python·pyspark·nebulagraph
九皇叔叔2 小时前
深度解析 PostgreSQL 中的 ctid、xmin、xmax:从原理到实战
数据库·postgresql
殷丿grd_志鹏2 小时前
开源项目RuoYi-Cloud-Plus详解——公网内网穿透到虚拟机环境(持续更新)
数据库·开源·内网穿透·虚拟机
木易 士心2 小时前
AI 在数据库操作中的各类应用场景、方案与实践指南
数据库·人工智能·oracle
SunsPlanter3 小时前
苍穹外卖--04--Redis 缓存菜品信息、购物车
数据库·redis·缓存
解决问题no解决代码问题4 小时前
oracle删除表与表空间清理机制
数据库·oracle
程序员三明治4 小时前
【Mybatis从入门到入土】ResultMap映射、多表查询与缓存机制全解析
java·sql·缓存·mybatis·resultmap·缓存机制·多表查询