Spring缓存能否对saveAll/updateAll应用Cacheable?缓存键如何配置?
关于Spring缓存在saveAll/updateAll方法中的应用
1. Spring缓存是否支持saveAll/updateAll操作?
完全支持。Spring缓存的@CachePut、@CacheEvict等注解可以直接应用在批量操作方法上,核心是要根据批量操作的特性,正确配置缓存键和缓存逻辑,确保集合中的每个元素都能和对应的缓存条目关联。
2. 缓存键的正确配置方案
针对updateAll/saveAll方法
你现有代码里的@CachePut配置存在问题:key="#projectTeam.id"中的projectTeam是List集合,本身没有id属性,会直接抛出异常。要处理集合中的每个元素,需要利用Spring EL的遍历特性,结合@CachePut的自动处理逻辑——当方法返回集合时,Spring会遍历集合,为每个元素生成对应的缓存条目。
修改后的代码示例:
@CachePut(cacheNames = "projectTeams", key = "#item.id") public List<ProjectTeam> updateAll(List<ProjectTeam> projectTeams) { return projectTeamRepository.saveAll(projectTeams); }
这里的#item代表返回集合中的单个ProjectTeam对象,Spring会自动遍历返回结果,将每个对象以其id作为key,更新projectTeams缓存中的对应条目。saveAll方法的缓存配置和这个完全一致,因为它既处理新增也处理更新,@CachePut会自动覆盖旧缓存或新增新条目。
针对findByIds方法
你现有代码的key="#id"是错误的,方法参数是ListOfIds<Long> ids,不存在id这个参数,需要调整key表达式:
- 如果希望按单个id缓存(提高缓存命中率),建议拆分出单个查询方法,批量查询时复用单个查询的缓存:
@Cacheable(cacheNames = "projectTeams", key = "#id") public ProjectTeam findById(Long id) { log.info("get project team from db by id: {}", id); return projectTeamRepository.findById(id).orElse(null); } public List<ProjectTeam> findByIds(ListOfIds<Long> ids) { return ids.getIds().stream() .map(this::findById) .collect(Collectors.toList()); }
- 如果坚持给批量查询方法直接加缓存,可以将整个id集合作为key(缓存的是整个查询结果,命中率较低,适合固定id组合的查询):
@Cacheable(cacheNames = "projectTeams", key = "#ids.getIds()") public List<ProjectTeam> findByIds(ListOfIds<Long> ids) { log.info("get project teams from db for ids: {}", ids.getIds()); return projectTeamRepository.findByIds(ids); }
3. 关键注意事项
- 确保
ProjectTeam类正确实现equals和hashCode方法,Spring缓存依赖这两个方法判断缓存条目是否一致。 - 使用
@CachePut处理批量操作时,返回的集合必须包含所有被操作的元素,否则Spring无法正确遍历更新缓存。
内容的提问来源于stack exchange,提问作者Ashish Rana
相关产品推荐
相关产品推荐

