我有一个需要缓存的作业列表(按ID)。但是,在某些情况下,拥有作业的最新版本很重要,并且需要绕过缓存(强制更新)。发生这种情况时,应将新获取的作业放置在缓存中。
我是这样实现的:
@Cacheable(cacheNames = "jobs", key = "#id", condition = "!#forceRefresh", sync = true)
public Job getJob(String id, boolean forceRefresh) {
// expensive fetch
}
所需行为:
getJob("123", false)
=>返回作业v1(如果存在,则从缓存中获取)getJob("123", true)
=>返回作业v2(更新版本,从数据库获取)getJob("123", false)
=>返回作业v2(更新的版本,从缓存中获取)实际上,最后一次调用getJob("123", false)
返回了旧版本的作业 v1 。似乎第二次调用(强制更新)没有更新缓存中的值。
如何在此处实现正确的行为?
缓存配置(使用咖啡因):
CaffeineCache jobs = new CaffeineCache("jobs", Caffeine.newBuilder()
.expireAfterWrite(1, TimeUnit.MINUTES)
.maximumSize(100)
.build());
答案 0 :(得分:1)
我之前遇到过这个问题,并通过两种方法解决了它。解决此问题的最简单方法是通过您正在使用的同一Job
完成对JobService
的所有更新。如果是这种情况,您只需执行以下操作:
@Caching(evict = {
@CacheEvict(value = "jobs", key = "#job.id") })
public void updateJob( Job job ) {
这样,在更新Job
时,它将在高速缓存中逐出,而您对getJob
的下一次调用将拉出一个新的
下一个方法是,如果您还有其他更新数据库的过程,而updateJob
不用于更新实际源。到那时,我已经实现了它,在那里我构建了一个Quartz Job来按计划(即每15分钟)刷新/更新我的缓存条目。看起来像这样。
@Autowired
CacheManager cacheManager;
public void refreshJobs() {
Cache cache = cacheManager.getCache( "jobs" );
for ( Job job : getJobs() ) {
cache.put( job.getId(), job );
}
}
使用该解决方案可能会得到一些过时的Jobs,但您知道它每5、10或15分钟就会刷新一次。
答案 1 :(得分:0)
如果forceRefresh
为true,则由于条件condition = "!#forceRefresh"
不会激活Spring缓存。因此,缓存值将不会更新。
在@CachePut
为真的情况下,您需要明确告诉Spring使用forceRefresh
更新缓存值:
@Caching(
cacheable = {@Cacheable(cacheNames = "jobs", key = "#id", condition = "!#forceRefresh")},
put = {@CachePut(cacheNames = "jobs", key = "#id", condition = "#forceRefresh")}
)
public Job getJob(String id, boolean forceRefresh) {
// expensive fetch
}