java - Spring Boot 使用 findAll 方法填充 findById 方法使用的缓存
问题描述
我在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 秒的等待时间?为什么会这样?没有错误,缓存不是变量,所以我发现很难调试这个问题,因为在调试会话期间我看不到缓存的内容。
解决方案
任何存储在缓存中的数据都需要一个键来快速检索。默认情况下,Spring 使用带注释的方法的签名作为键来创建缓存键。
所以在这里你基本上使用了两种不同的方法,它们将使用单独的键,即方法签名。因此,如果您再次调用相同的方法,那么结果将从缓存中返回,而不是从数据库中获取数据。我希望你能明白。您可以查看以下链接
而且您的期望是完全错误的,如上所述,每个缓存都需要一个 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);
}
}
您必须在启动时调用它。而已。
推荐阅读
- excel - 使用和激活多个工作簿的问题 excel VBA
- python - 如何创建一个元组的元组,其中在python中分配了变量
- terraform - 每个循环或 for 循环的 Terraform 不起作用
- java - 对 NamedParameterJdbcTemplate 的引用不明确,batchUpdate(String,Map
[]) 和 batchUpdate(String,SqlParameterSource[]) 匹配 - c++ - 如何用 CUB 库编译 C++?
- css - 布尔玛限制?
- python - DeepSearch - 仅返回索引号
- qt - QML 没有从另一个文件中的单例获取属性
- javascript - jquery嵌套时找不到id,但不嵌套时找到
- r - 根据R中同一行的另一列中单元格的值对一列求和