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
你的期望是完全错误的,正如上面所说的,每个缓存都需要一个 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);
}
}
你必须在启动时调用它。就是这样。
我在 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
你的期望是完全错误的,正如上面所说的,每个缓存都需要一个 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);
}
}
你必须在启动时调用它。就是这样。