Java第十二篇:关于RedisTemplate取String类型的value转对象出现的SerializationException问题解决

本文介绍了解决Spring Boot项目中RedisTemplate序列化导致的异常问题,包括配置调整及如何避免自定义序列化带来的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题背景

  • SpringBoot项目,整合了spring-boot-starter-data-redis
  • 通过配置RedisTemplate来进行redis Key的增删查改操作
  • 将对象存入redis成功(对象中还包含对象)
    在这里插入图片描述

问题是:但是取出来的时候转成AuthInfo对象报错了!!!
异常如下:

org.springframework.data.redis.serializer.SerializationException: Could not read JSON: Cannot construct instance of `com.zt.space.security.vo.JwtUser` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
 at [Source: (byte[])"["com.zt.}]"; line: 1, column: 331] (through reference chain: com.zt.space.security.vo.AuthInfo["jwtUser"]); nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.zt.space.security.vo.JwtUser` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
 at [Source: (byte[])")
	at org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer.deserialize(Jackson2JsonRedisSerializer.java:75)
...

原因

序列化原因!!!

解决方案

中途经历许多波折和探索,就不一一叙述了,直接上解决方案

第一步

先查看自己的RedisTemplate配置,有没有手动设置了序列化?
我也是参考另一篇博客的解答:Redis使用过程出现类型转换异常问题- 20190220
一看我自己的配置如下(网上照搬的。由此可见网上的东西坑货还是挺多的):

	@Bean
    @SuppressWarnings("all")
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {

        RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();

        template.setConnectionFactory(factory);

        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);

        ObjectMapper om = new ObjectMapper();

        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);

        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

        jackson2JsonRedisSerializer.setObjectMapper(om);

        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();

        // key采用String的序列化方式

        template.setKeySerializer(stringRedisSerializer);

        // hash的key也采用String的序列化方式

        template.setHashKeySerializer(stringRedisSerializer);

        // value序列化方式采用jackson

        template.setValueSerializer(jackson2JsonRedisSerializer);

        // hash的value序列化方式采用jackson

        template.setHashValueSerializer(jackson2JsonRedisSerializer);

        template.afterPropertiesSet();

        return template;

    }

根据那篇博文的解释:RedisTemplate已经默认使用序列化了,我去看了下源码,还真是的,可能是以前的老版本不是。
所以根本不需要自己在手动设置,修改如下:

	@Bean
    @SuppressWarnings("all")
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {

        RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();

        template.setConnectionFactory(factory);

        return template;

    }

这个时候已经存取正常了
但是,人生总是会有意外惊喜
我去RDM中查看存的数据情况,如下:

在这里插入图片描述

完全无法查看json,感觉是乱码,但是实际上你通过java代码取出来的是正常的,只是无法通过RDM查看
初步估计是序列化的格式不对

### Spring Cacheable 导致 SerializationException解决方案 当使用 `@Cacheable` 注解时,如果发生序列化异常(如 `SerializationException`),通常是因为缓存的数据无法被正确序列化或反序列化。以下是可能的原因以及对应的解决办法: #### 原因分析 1. **JSON 数据格式不匹配** 如果 Redis 中存储的对象不符合预期的 JSON 格式,则会抛出类似于 `Could not read JSON: Unexpected token (START_OBJECT)` 或 `(VALUE_STRING)` 的错误消息[^2]。 2. **实体类未实现 Serializable 接口** 缓存对象需要支持序列化操作,因此实体类应显式实现 `Serializable` 接口。否则,在尝试将对象写入 Redis 时可能会失败[^1]。 3. **RedisTemplate 配置不当** 默认情况下,Spring Data Redis 使用的是 `JdkSerializationRedisSerializer` 进行序列化/反序列化处理。然而,这种默认配置可能导致复杂数据结构难以解析。可以考虑切换到其他更友好的序列化器,比如 Jackson 序列化器[^3]。 4. **键绑定方式问题** 错误地调用了某些实验性的 API 方法(例如 `redisTemplate.boundValueOps()`),这可能导致后续读逻辑出现问题。务必确认代码路径是否一致并清理残留测试代码。 --- #### 解决方案 ##### 方案一:调整实体类定义 确保所有参与缓存的对象都实现了 `java.io.Serializable` 接口,并提供无参构造函数以便于实例化。 ```java import java.io.Serializable; public class UserInfo implements Serializable { private static final long serialVersionUID = 1L; private Long id; private String name; // Getter and Setter methods omitted here... } ``` ##### 方案二:修改 RedisTemplate 配置 通过自定义 RedisTemplate 来指定更加灵活的序列化策略。推荐采用基于 Jackson 的序列化工具来提升兼容性和可维护性。 ```java @Configuration public class RedisConfig { @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) { RedisTemplate<String, Object> template = new RedisTemplate<>(); // 设置 key 和 value 的序列化方式 template.setKeySerializer(new StringRedisSerializer()); template.setValueSerializer(new GenericJackson2JsonRedisSerializer()); template.setHashKeySerializer(new StringRedisSerializer()); template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer()); template.setConnectionFactory(connectionFactory); return template; } } ``` ##### 方案三:排查业务代码中的潜在隐患 仔细检查是否有遗留下来的调试代码干扰正常流程。例如: ```java // 下面这段代码可能是为了临时验证功能而加入的, // 它绑定了特定 Key 并设置了过期时间,但如果没有及时移除, // 可能会影响全局行为。 redisTemplate.boundValueOps(token).set(userInfo, 1L); ``` 建议删除此类不必要的片段或者将其封装成独立的服务单元以减少副作用。 ##### 方案四:优化缓存注解参数设置 合理设计 `@Cacheable` 的方法签名及其关联属性,尤其是返回类型的声明要清晰准确。同时注意避免嵌套复杂的集合类型作为输入输出参数。 ```java @Service public class UserService { @Autowired private UserRepository userRepository; @Cacheable(value = "users", unless = "#result == null") public UserInfo getUserInfoById(Long userId) { return userRepository.findById(userId).orElse(null); } } ``` --- ### 总结 上述四种措施分别针对不同层面的问题提出了改进意见。实际应用过程中可以根据具体情况组合运用这些技巧解决问题。最终目标是让整个系统能够稳定高效运行的同时满足高性能需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值