有没有办法分别为 saveAll 或 updateAll 应用 Cacheable 功能的 Spring 缓存功能?

问题描述 投票:0回答:1
@CachePut(cacheNames = "projectTeams", key = "#projectTeam.id")
public List<ProjectTeam> updateAll(List<ProjectTeam> projectTeam) {
   return projectTeamRepository.save(projectTeam);
}


@Cacheable(cacheNames = "projectTeams", key = "#id")
public List<ProjectTeam> findByIds(ListOfIds<Long> ids) {
log.info("get project team from db");
log.info("projectTeam id " + id);
return projectTeamRepository.findByIds(ids);
} 

我不知道我应该输入什么键。 spring缓存是否支持SaveAll。

java spring-boot caching spring-cache trending
1个回答
1
投票

Spring 使用默认密钥生成策略,根据方法的参数,从启用缓存的(

@Cacheable
@CachePut
注释)服务或存储库方法中派生缓存条目的密钥。

当然,您可以通过 1) 实现 KeyGenerator 接口

 和 2) 在缓存注释中声明 
KeyGenerator bean,来
自定义任何启用缓存的 bean 方法使用的密钥生成
,如下所示:

class ListKeyGenerator implements KeyGenerator {

  public Object generate(Object target, Method method, Object... params) {

    List<?> list = params[0];

    // use the list to generate a (unique) key for the cache entry
    Object generatedKey = ...;

    return generatedKey;
  }
}

注意:

target
是包含
updateAll(..)
findByIds(..)
方法的 Spring 托管 bean。
Method
ref 是调用的启用缓存的方法,例如
updateAll(..)
。并且,对象参数数组是启用缓存的方法的参数(例如
List
)。

提示:为了简单和清晰(推荐),您可能需要 2 个独立的基于

List
KeyGenerators
,因为 1 是
List
ID(
Long
类型;在查找/查询方法中)并且另一个是
List
ProjectTeam
实例(在更新中)。

在配置中,您可以声明:

@Configuration
class ApplicationCacheConfiguration {


  @Bean
  KeyGenerator listKeyGenerator() {
    return new ListKeyGenerator();
  }
}

您可以使用以下方式应用自定义

KeyGenerator

@Service
class ProjectTeamService {

  @CachePut(cacheNames = "projectTeams" keyGenerator = "listKeyGenerator")
  public List<ProjectTeam> updateAll(List<ProjectTeam> projectTeams) {
    // perform any preprocessing steps as necessary
    return this.projectTeamRepository.saveAll(projectTeams);
  }
}

注意:请参阅相应的 Javadoc 了解

@Cacheable
Javadoc 了解
@CachePut

但是,如果您只是依赖 Spring 的

 默认密钥生成 
策略(正如我一开始提到的那样),则不一定需要自定义 KeyGenerator

关于您选择的方法,这将不起作用,因为它试图使用 Spring SpEL 表达式来访问

ProjectTeam
对象中的
List
中的单个元素/项目(即单个
ProjectTeam
实例)。这同样适用于 ID 的
List

您使用

List
中的哪个元素?您是否使用所有元素(使用 SpEL 很难聚合这些元素)?如果启用缓存的方法的
List
参数为空,或更糟糕的是
null
,会发生什么?

提示:您应该查看 Spring 的 SpEL 功能以了解更多详细信息。

这些问题在您的自定义

KeyGenerator
实现中得到更妥善的处理。

您还应该知道,Spring 托管 bean 的启用缓存方法的缓存条目将是(使用“默认密钥生成”):

cache-enabled method          | cache key         | cache value
----------------------------------------------------------------------
findByIds(:List<Long>)        | List<Long>        | List<ProjectTeam>
updateAll(:List<ProjectTeam>) | List<ProjectTeam> | List<ProjectTeam>

如果您期望

Long
的各个元素/项目(例如
ProjectTeam
ID 或
Lists
实例)被分解并单独缓存在单独的缓存条目中,那么您就错了,因为这不是 Spring 的缓存抽象默认工作。

我提到这一点的原因是因为它是由注释中声明的(尝试的)缓存配置所暗示的。

Spring 将参数传递给启用缓存的方法(例如

@Cacheable
带注释的方法),并将其用作缓存条目的键。该方法的返回值用作值。由于启用缓存的方法采用
List
并返回
List
,因此缓存条目键是
List
参数,而
List
返回值是缓存条目值。

正如您可能想象的那样,随着请求每个不同的

List
ID 或
List
ProjectTeam
实例,您的缓存空间将很快填满!这是因为,如果每个请求(缓存启用方法)中的
List
仅相差 1 个元素,那么这将在缓存中构成一个新的缓存条目。根据您的应用程序处理的(不同)请求(调用)数量和频率,这可能会导致严重的问题(例如 OOME)!

如果您需要单独请求的项目的单独缓存条目,那么您应该看看这篇之前的帖子

祝你好运!

© www.soinside.com 2019 - 2024. All rights reserved.