Spring 缓存:根据条件强制更新缓存
Spring Cache: force update cache based on condition
我有一个需要缓存的作业列表(按 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)
returns 作业 v1,旧版本。好像第二次调用(强制更新)没有更新缓存中的值。
我怎样才能在这里实现正确的行为?
缓存配置(使用咖啡因):
CaffeineCache jobs = new CaffeineCache("jobs", Caffeine.newBuilder()
.expireAfterWrite(1, TimeUnit.MINUTES)
.maximumSize(100)
.build());
我以前 运行 解决过这个问题,并用几种方法解决了它。解决它的最简单方法是通过您正在使用的 JobService
完成对 Job
的所有更新。如果是这种情况,您只需这样做:
@Caching(evict = {
@CacheEvict(value = "jobs", key = "#job.id") })
public void updateJob( Job job ) {
这样,当 Job
更新时,它将在缓存中被逐出,您下次调用 getJob
时将提取一个新的。
下一种方法是,如果您有一些其他进程正在更新您的数据库,并且 updateJob
未用于更新实际源。那时,我已经实现了它,我在其中构建了一个 Quartz Job 以按计划 refresh/update 我的缓存条目(即每 15 分钟)。它看起来像这样。
@Autowired
CacheManager cacheManager;
public void refreshJobs() {
Cache cache = cacheManager.getCache( "jobs" );
for ( Job job : getJobs() ) {
cache.put( job.getId(), job );
}
}
您可能会使用该解决方案获得一些陈旧的作业,但您知道它每 5、10 或 15 分钟刷新一次。
如果forceRefresh
为真,Spring缓存不会因为条件condition = "!#forceRefresh"
而被激活。因此,缓存值不会被更新。
您需要明确告诉 Spring 使用 @CachePut
更新缓存值,以防 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
}
我有一个需要缓存的作业列表(按 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)
returns 作业 v1,旧版本。好像第二次调用(强制更新)没有更新缓存中的值。
我怎样才能在这里实现正确的行为?
缓存配置(使用咖啡因):
CaffeineCache jobs = new CaffeineCache("jobs", Caffeine.newBuilder()
.expireAfterWrite(1, TimeUnit.MINUTES)
.maximumSize(100)
.build());
我以前 运行 解决过这个问题,并用几种方法解决了它。解决它的最简单方法是通过您正在使用的 JobService
完成对 Job
的所有更新。如果是这种情况,您只需这样做:
@Caching(evict = {
@CacheEvict(value = "jobs", key = "#job.id") })
public void updateJob( Job job ) {
这样,当 Job
更新时,它将在缓存中被逐出,您下次调用 getJob
时将提取一个新的。
下一种方法是,如果您有一些其他进程正在更新您的数据库,并且 updateJob
未用于更新实际源。那时,我已经实现了它,我在其中构建了一个 Quartz Job 以按计划 refresh/update 我的缓存条目(即每 15 分钟)。它看起来像这样。
@Autowired
CacheManager cacheManager;
public void refreshJobs() {
Cache cache = cacheManager.getCache( "jobs" );
for ( Job job : getJobs() ) {
cache.put( job.getId(), job );
}
}
您可能会使用该解决方案获得一些陈旧的作业,但您知道它每 5、10 或 15 分钟刷新一次。
如果forceRefresh
为真,Spring缓存不会因为条件condition = "!#forceRefresh"
而被激活。因此,缓存值不会被更新。
您需要明确告诉 Spring 使用 @CachePut
更新缓存值,以防 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
}