Redis序列化的问题:Failed to deserialize object type

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: 您好,我是码农飞哥,感谢您阅读本文!最近在进行框架改造,历史遗留代码对Redis的使用不当,导致了一些问题。

您好,我是码农飞哥,感谢您阅读本文!最近在进行框架改造,历史遗留代码对Redis的使用不当,导致了一些问题。

问题描述

org.springframework.data.redis.serializer.SerializationException: Cannot deserialize; nested exception is org.springframework.core.serializer.support.SerializationFailedException: Failed to deserialize payload. Is the byte array a result of corresponding serialization for DefaultDeserializer?; nested exception is org.springframework.core.NestedIOException: Failed to deserialize object type; nested exception is java.lang.ClassNotFoundException: com.coep.model.domain.UserCache
  at org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.deserialize(JdkSerializationRedisSerializer.java:84)

从问题的描述我们就可以轻松的定位到这是由于调用JdkSerializationRedisSerializer的deserialize方法对redis值进行反序列化时报的错。

问题分析

错误提示是ClassNotFoundException: com.coep.model.domain.UserCache,这个UserCache类找不到了,为啥找不到呢,这是由于我们在进行框架改造时变更了类的包名。所以,反序列化类时就找不到了。原有的对redis的操作类。

对redis使用的错误示范

private static RedisSerializer<Object> jdkRedisSerializer = new JdkSerializationRedisSerializer();
    private static RedisSerializer<String> stringRedisSerializer = new StringRedisSerializer();
public boolean set(final String key, final Object obj, final long seconds) {
        // key的组织形式 namespace:id:parmeter
        strRedisTemplate.execute((RedisCallback<Serializable>) connection -> {
            final byte[] keyBytes = stringRedisSerializer.serialize(key);
            final byte[] name = jdkRedisSerializer.serialize(obj);
            connection.setEx(keyBytes, seconds, name);
            return null;
        });
        return true;
    }
   @Override
    public Serializable get(final Serializable key) {
        return strRedisTemplate.execute((RedisCallback<Serializable>) connection -> {
            byte[] keyBytes = stringRedisSerializer.serialize( key);
            byte[] bytes = connection.get(keyBytes);
            return (Serializable) jdkRedisSerializer.deserialize(bytes);
        });
    }

这里设置键值时,对key使用的是StringRedisSerializer进行序列化,对value使用的是JdkSerializationRedisSerializer进行序列化。序列化后的数据类型是二进制的字节码文件,可视性差。而且使用JdkSerializationRedisSerializer序列化性能比较差,所以不推荐使用。

88acfca4e1946093fa0b8b072ea31990_watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ1MzQ4MDg=,size_16,color_FFFFFF,t_70.png

正确的姿势

对于历史的记录,只能在报错之后删除掉该key。这里推荐使用StringRedisSerializer来序列化key和value。相关的配置如下:

使用RedisTemplate操作类的配置如下:

@Primary
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        try {
            //测试连通性
            factory.getConnection();
        } catch (RedisConnectionFailureException e) {
            LOGGER.warn("未发现redis服务。");
            redisAvailable = false;
        }
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new StringRedisSerializer());
        redisTemplate.setConnectionFactory(factory);
        return redisTemplate;
    }

或者直接使用StringRedisTemplate操作类的配置如下:

@Bean
    public StringRedisTemplate stringRedisTemplate(JedisConnectionFactory redisConnectionFactory) {
        StringRedisTemplate stringRedisTemplate = new StringRedisTemplate(redisConnectionFactory);
        return stringRedisTemplate;
    }


相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
1月前
|
NoSQL 测试技术 Go
【Golang】国密SM2公钥私钥序列化到redis中并加密解密实战_sm2反编(1)
【Golang】国密SM2公钥私钥序列化到redis中并加密解密实战_sm2反编(1)
|
18天前
|
存储 NoSQL Redis
Redis第四弹,Redis实现list时候做出的优化ziplist(压缩链表,元素少的情况),可更好的节省空间list——(内部编码:quicklist)Object encoding
Redis第四弹,Redis实现list时候做出的优化ziplist(压缩链表,元素少的情况),可更好的节省空间list——(内部编码:quicklist)Object encoding
|
18天前
|
消息中间件 NoSQL Redis
Redis第三弹,定时删除1.优先级队列(堆)2.基于时间轮实现的定时器​编辑Type指令(返回key对应的数据类型)redis的数据类型hset key field value
Redis第三弹,定时删除1.优先级队列(堆)2.基于时间轮实现的定时器​编辑Type指令(返回key对应的数据类型)redis的数据类型hset key field value
|
1月前
|
JSON NoSQL Java
SpringDataRedis 操作 Redis,并指定数据序列化器
SpringDataRedis 操作 Redis,并指定数据序列化器
27 1
|
1月前
|
存储 JSON NoSQL
[Redis]——RedisTemplate的两种序列化方式
[Redis]——RedisTemplate的两种序列化方式
137 0
|
1月前
|
缓存 NoSQL Java
Spring Data Redis对象缓存序列化问题
在使用 Redis 时,有没有遇到同我一样,对象缓存序列化问题的呢?
85 6
Spring Data Redis对象缓存序列化问题
|
1月前
|
XML 存储 JSON
C# 对象存储 (轻松实现序列化 | Xml | Json | 加密 | 压缩 | 注册表 | Redis)
开发时经常会遇到需要保存配置的情况,最常见的实现方式是将对象序列化成Json,再写入文件并保存到本地磁盘。 本文将使用开源库**ApeFree.DataStore**来替换原有的对象存储过程,实现一个可以随意切换存储方式的对象存储方法。 ApeFree.DataStore是一款可配置的对象存储库,支持在不同平台/介质中对内存中的对象进行存储与还原(如本地存储、注册表存储)。支持配置序列化格式(如Json、Xml),支持配置压缩算法(如GZip、Defalte),支持配置加密算法(如AES、RSA)。
80 0
C# 对象存储 (轻松实现序列化 | Xml | Json | 加密 | 压缩 | 注册表 | Redis)
|
1月前
|
存储 缓存 NoSQL
SpringBoot整合Redis调用lua脚本出现空指针异常(序列化器问题)
一、问题描述 业务中出现需要保证原子性的一系列缓存操作,所以决定使用lua脚本来保证原子性。 但是调用过程中lua脚本抛出了异常:attempt to perform arithmetic on local ‘xxx’ (a nil value) 发生异常的lua脚本代码(部分)
|
1月前
|
NoSQL Linux Redis
Redis -- 安装客户端redis-plus-plus
Redis -- 安装客户端redis-plus-plus
55 0
|
5天前
|
NoSQL Redis Windows
win10下Redis安装、启动教程
win10下Redis安装、启动教程
14 2