@Cacheable org.springframework.data.redis.serializer.SerializationException: Could not read JSON: Unexpected token (START_OBJECT), expected VALUE_STRING: need String, Number of Boolean value that contains type id (for subtype of java.lang.Object)
时间: 2025-03-13 07:07:47 浏览: 257
### 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);
}
}
```
---
### 总结
上述四种措施分别针对不同层面的问题提出了改进意见。实际应用过程中可以根据具体情况组合运用这些技巧解决问题。最终目标是让整个系统能够稳定高效运行的同时满足高性能需求。
阅读全文
相关推荐



















