Spring缓存-仅当API响应成功时才清除缓存
我正在使用SpringCacheSpring缓存-仅当API响应成功时才清除缓存,spring,spring-boot,caching,Spring,Spring Boot,Caching,我正在使用SpringCache@cacheexecute&@Cacheable 目前,我每小时运行一次调度程序以清除缓存,下次调用fetchUser()时,它将从外部APi获取数据并添加到缓存中 @Scheduled(cron = "0 0 * * * *}") @CacheEvict(value = "some-unique-value", allEntries = true) public void clearUserCache() { lo
@cacheexecute
&@Cacheable
目前,我每小时运行一次调度程序以清除缓存,下次调用fetchUser()时,它将从外部APi获取数据并添加到缓存中
@Scheduled(cron = "0 0 * * * *}")
@CacheEvict(value = "some-unique-value", allEntries = true)
public void clearUserCache() {
log.info("Cache cleared");
}
@Cacheable(value = "some-unique-value", unless = "#result.isFailure()")
@Override
public Result<UserResponse> fetchUser() {
try {
UserResponse userResponse = api.fetchUserDetail();
return Result.success(userResponse);
} catch (Exception e) {
return Result.failure(INTERNAL_SERVER_ERROR);
}
}
@Scheduled(cron=“0****}”)
@cacheexecute(value=“某些唯一值”,allEntries=true)
public void clearUserCache(){
log.info(“缓存已清除”);
}
@可缓存(value=“某些唯一值”,除非=“#result.isFailure()”)
@凌驾
公共结果fetchUser(){
试一试{
UserResponse UserResponse=api.fetchUserDetail();
返回Result.success(userResponse);
}捕获(例外e){
返回结果。失败(内部服务器错误);
}
}
现在我们需要的是仅当用户API调用成功时才清除缓存。有没有办法做到这一点
现在,缓存已按计划清除,假设外部API调用失败。主API将返回错误响应。在这种情况下,我应该能够使用现有的缓存本身。如果我得到了正确的缓存,为什么不在检查此方法的父级的API调用是否正确后,将其作为普通方法调用呢 用你的代码,一些类似于
//如果您需要,我们只需在这里安排时间。
@已计划(cron=“0****}”)
@cacheexecute(value=“某些唯一值”,allEntries=true)
public void clearUserCache(){
log.info(“缓存已清除”);
}
@可缓存(value=“某些唯一值”,除非=“#result.isFailure()”)
@凌驾
公共结果fetchUser(){
试一试{
UserResponse UserResponse=api.fetchUserDetail();
返回Result.success(userResponse);
}捕获(例外e){
返回结果。失败(内部服务器错误);
}
}
公共方法(){
Result userResult=this.fetchUser();
if(userResult.isFailure()){
这个.clearUserCache();
}
}
这样,如果抛出任何异常
,它将返回一个失败
状态,您可以检查它。因此,缓存将每小时被清除一次,或者在缓存不工作时被清除一次
因此,下一次,由于失败且没有缓存,它将重试。我没有找到任何直接的实现,但通过改进,我能够做到这一点 用例
- 只有在触发下一个使用用户API的服务调用时,才应更新用户API响应。调度程序不应更新它。因为我们需要将来自外部系统的头信息传递给用户API
- 只有当用户API响应成功时,才能清除缓存
- 在调度程序中添加了一个变量,并在缓存更新时在调度时间和关闭时间将其打开
- 此标志在
类中用于检查是否触发了调度程序UserService
- 如果没有,请使用缓存。如果
,则触发用户API调用。如果成功,请检查响应。触发cacheexecute方法并更新缓存true
@Cacheable(value=“USER_CACHE”,key=“#root.targetClass”,除非=“#result.isFailure()”)
公共结果getUserDetail(UserResponse UserResponse){
试一试{
如果(userResponse==null){//在缓存不可用时处理第一次触发器
userResponse=fetchUserDetail();//实际的API调用
}
返回Result.success(mapToUser(userResponse));
}捕获(例外e){
返回结果。失败(“错误响应”);
}
}
注意:
- 结果是一个自定义包装器,假设它是一个具有成功或失败属性的对象
- 我不得不添加
部分作为单独的Bean,因为缓存只在代理对象上工作。如果我将@Cacheable
保存在getUserDetail
中并直接调用,则它不会被拦截,因为代理和缓存逻辑不工作,每次都会触发API调用UserService
- 最重要的是:这不是最好的解决方案,还有改进的余地
@Cacheable
,这意味着,它将从缓存中读取数据,而不会进行实际的Rest调用。我说的对吗?调度程序不是用户API调用的触发点。它将使用userAPI从服务中调用,并且只有当该服务由外部系统触发时才调用。只是有一点偏差。唯一的问题是,如果缓存已经就位,您将永远无法访问“this.clearUserCache();”。Spring将返回代理对象,而不是调用实际方法。此外,由于数据需要通过任何后续API调用每小时刷新post,因此需要调度程序。我修复了我的答案。父级将调用this.fetchUser()
,如果上一次迭代不起作用,或者已经过了一个小时,它将再次调用该方法。或者您需要对照当前迭代检查它吗?2偏差1。如果在每小时清除一次缓存,并且UserAPI关闭,则整个响应将失败。这违背了目的。2.parentMethod()不应该是空的,检查是(!userResult.isFailure()){我想你漏掉了“不是”。但总的来说,它与我实现的一致。很快就会发布。谢谢。
private boolean updateUserCache;
@Scheduled(cron = "${0 0 * * * *}") // runs every Hr
public void userScheduler() {
updateUserCache = true;
log.info("Scheduler triggered for User");
}
@CacheEvict(value = "USER_CACHE", allEntries = true)
public void clearUserCache() {
updateUserCache = false;
log.info("User cache cleared");
}
public boolean isUserCacheUpdateRequired() {
return updateUserCache;
}
UserResponse userResponse = null;
if (schedulerConfig.isUserCacheUpdateRequired()) {
userResponse = userCache.fetchUserDetail();
if (userResponse != null) {
// clear's cache and userResponse is stored in cache automatically when getUserDetail is called below
schedulerConfig.clearUserCache();
}
}
return userCache.getUserDetail(userResponse);
@Cacheable(value = "USER_CACHE", key = "#root.targetClass", unless = "#result.isFailure()")
public Result<User> getUserDetail(UserResponse userResponse) {
try {
if (userResponse == null) { // handle first time trigger when cache is not available
userResponse = fetchUserDetail(); // actual API call
}
return Result.success(mapToUser(userResponse));
} catch (Exception e) {
return Result.failure("Error Response");
}
}