Spring 使用 findAll 方法引导填充 findById 方法使用的缓存

Spring boot populating cache used by findById method with findAll method

我在 springboot 应用程序中有一个简单的服务,其中一种方法通过 Id(主键)从数据库中获取一个对象。我还有另一种方法 returns table 中的所有对象。

@Cacheable("stores")
public List<Store> findAllStores() throws InterruptedException {
    Thread.sleep(5000);
    return storeRepository.findAll();
}

@Cacheable("stores")
public Store findById(int storeId) throws InterruptedException {
    Thread.sleep(5000);
    return storeRepository.findById(storeId).orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST, "No store with specified ID exist"));
}

在我的测试中,我调用了第一个方法,该方法使用 table 中的所有商店对象填充名为“stores”的缓存,但是当我调用第二个方法通过 Id 单独查找商店时,我还有 5 秒的等待时间吗?为什么会这样?没有错误并且缓存不是变量,所以我发现很难调试这个问题,因为在调试会话期间我看不到缓存的内容。

缓存中存储的任何数据都需要一个密钥才能快速检索。 Spring,默认情况下,使用注释方法的签名作为密钥来创建缓存密钥。

所以在这里你基本上使用了两种不同的方法,它们将使用单独的密钥,即方法签名。因此,如果您再次调用相同的方法,那么结果将从缓存中返回,而不是从数据库中获取数据。 我希望你能明白。您可以查看下方link

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/cache/annotation/Cacheable.html#:~:text=Annotation%20Type%20Cacheable&text=Annotation%20indicating%20that%20the%20result,invoked%20for%20the%20given%20arguments.

你的期望是完全错误的,正如上面所说的,每个缓存都需要一个 cacheKey 并且它根据该键存储值,如果你执行你的第二种方法 - 第一次你从 storeId 获取 Store 并且它保存在带有方法签名的缓存中作为键,它也将 storeId 作为键,所以第二次调用相同的方法时,它将从缓存中获取它,因为它已经有该键的条目。 第一种方法和第二种方法的密钥不同,所以你的期望是错误的。

<---->编辑<--->

您可以像下面这样修改您的代码,明确指定 cacheID。

@Cacheable("stores",key = "#storeId")
public Store findById(int storeId) throws InterruptedException {
   
    return storeRepository.findById(storeId).orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST, "No store with specified ID exist"));
}

删除不需要的 findAllStores() 方法。并直接使用 cacheManager 来存储值。如下所示。

@Autowired
 CacheManager cacheManager;
@Autowired
 StoreRepository repo;

public void loadCache() {
  for(Store store:repo.getAll()) {
    cacheManager.getCache("stores").put(store.getId(),store);
  }
}

你必须在启动时调用它。就是这样。