Spring Boot集成Redis缓存时@Cacheable/@CachePut序列化失败问题
Redis缓存序列化错误解决方案
问题原因
你的@Cacheable和@CachePut注解标注在Controller层方法上,这些方法返回的是ResponseEntity<AccountDTO>——这是Spring的HTTP响应包装类,默认Redis缓存序列化器(JdkSerializationRedisSerializer)无法正确序列化该类型;另外,若你的AccountDTO未实现Serializable接口,也会触发序列化失败。而@CacheEvict仅执行缓存键删除操作,无需序列化对象,因此功能正常。
解决方案
方案1:将缓存注解移至Service层(推荐)
缓存的核心是业务数据而非HTTP响应,将缓存注解放在Service层,直接缓存AccountDTO对象,更符合业务逻辑:
修改Service层代码
@Service @AllArgsConstructor @CacheConfig(cacheNames = "account") public class AccountService { private AccountRepository repository; private ModelMapper mapper; // 缓存根据用户名查询的AccountDTO @Cacheable(key = "#name") public AccountDTO getAccount(String name) { Account account = repository.findByHolderName(name); return mapper.map(account, AccountDTO.class); } // 更新缓存中的账户数据 @CachePut(key = "#id") public AccountDTO deposit(Long id, Double value) { Account account = repository.findById(id) .orElseThrow(() -> new RuntimeException("账户不存在")); account.setBalance(account.getBalance() + value); repository.save(account); return mapper.map(account, AccountDTO.class); } }
修改Controller层代码
移除Controller层的@Cacheable和@CachePut注解:
@Controller @RequestMapping("bank") @AllArgsConstructor @CacheConfig(cacheNames = "account") public class AccountController { private AccountService service; // ... 其他方法不变 @GetMapping("holderName/{name}") public ResponseEntity<AccountDTO> getAccountByName(@PathVariable String name){ return new ResponseEntity<>(service.getAccount(name),HttpStatus.ACCEPTED); } @PutMapping("{id}/deposit") public ResponseEntity<AccountDTO> deposit(@PathVariable Long id, @RequestBody Map<String, Double> request){ Double value = request.get("balance"); return new ResponseEntity<>(service.deposit(id,value), HttpStatus.ACCEPTED); } // ... 其他方法不变 }
方案2:配置Redis Jackson序列化器(若坚持在Controller层缓存)
若需在Controller层缓存ResponseEntity<AccountDTO>,需配置Redis使用Jackson序列化器,并确保AccountDTO实现Serializable:
1. 让AccountDTO实现Serializable
@Data @AllArgsConstructor @NoArgsConstructor public class AccountDTO implements Serializable { private Long id; private String holderName; private double balance; }
2. 添加Redis缓存配置类
@Configuration @EnableCaching public class RedisCacheConfig { @Bean public RedisCacheConfiguration cacheConfiguration() { return RedisCacheConfiguration.defaultCacheConfig() // 设置缓存过期时间 .entryTtl(Duration.ofMillis(60000)) // 键使用字符串序列化 .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())) // 值使用Jackson序列化 .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new Jackson2JsonRedisSerializer<>(Object.class))) // 不缓存null值 .disableCachingNullValues(); } }
额外检查点
- 确认Redis服务正常运行,端口、主机配置与
application.properties一致 - 若使用Jackson序列化,需确保项目中有
com.fasterxml.jackson.core:jackson-databind依赖(Spring Boot starter通常已包含)
内容的提问来源于stack exchange,提问作者Sakib X Hossain
相关产品推荐
相关产品推荐

