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

时间:2021-05-23 21:10:34

标签: java spring spring-boot caching spring-data-jpa

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

@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"));
}

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

1 个答案:

答案 0 :(得分:1)

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

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

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);
  }
}

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