如何使用Google Guava自动刷新缓存?

K. *_*ddy 30 java caching guava

我正在使用Google Guava库进行缓存.对于自动缓存刷新,我们可以执行以下操作:

cache = CacheBuilder.newBuilder()               
                    .refreshAfterWrite(15, TimeUnit.MINUTES)
                    .maximumSize(100)
                    .build(....);
Run Code Online (Sandbox Code Playgroud)

但是,当第一个条目的陈旧请求发生时,将执行自动刷新.

有没有办法自动刷新它,即使没有缓存数据的请求?就像每15分钟一样,缓存数据应该从Db中提取并加载它,无论是否有人调用缓存数据.

此外,Guava的缓存到期时间适用于整个缓存.是否可以基于密钥使缓存值失效?像密钥"NOT_SO_FREQ_CHANGE_DATA"的缓存数据每1小时到期一次,密钥"FREQ_CHANGING_DATA"的数据应该每15分钟到期一次?

Fra*_*eau 26

Guava无法批量刷新缓存,但您可以自行安排定期刷新:

LoadingCache<K, V> cache = CacheBuilder.newBuilder()
        .refreshAfterWrite(15, TimeUnit.MINUTES)
        .maximumSize(100)
        .build(new MyCacheLoader());

for (K key : cache.asMap().keySet()) {
    cache.refresh(key);
}
Run Code Online (Sandbox Code Playgroud)

但在这种情况下,您可能希望覆盖该CacheLoader.reload(K, V)方法,MyCacheLoader以便它以异步方式执行.

至于第二个问题,不,你不能在番石榴中设置每个条目的到期日.

  • 仅供参考,Guava [issue 971]正在讨论批量缓存刷新操作(http://code.google.com/p/guava-libraries/issues/detail?id=971&q=bulk%20refresh&colspec=ID%20Stars%20Type% 20Status%20Package%20Summary). (9认同)

Çağ*_*ürk 7

带并行流的JAVA 8版本:

Executors
        .newSingleThreadScheduledExecutor()
        .scheduleWithFixedDelay(() -> configurationCache
                .asMap()
                .keySet()
                .parallelStream()
                .forEach((key) -> configurationCache.refresh(key)),
            0,
            1, TimeUnit.SECONDS);
Run Code Online (Sandbox Code Playgroud)


McK*_*led 6

第一个问题.使用计划执行程序启动定期刷新.

第二个问题.如果您可以从缓存密钥或先前缓存的值推断出到期策略,则可以按不同的时间间隔刷新数据.

基于此:https: //code.google.com/p/guava-libraries/wiki/CachesExplained#Refresh

LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()
   .refreshAfterWrite(1, TimeUnit.MINUTES)
   .build(
       new CacheLoader<Key, Graph>() {
         public Graph load(Key key) { // no checked exception
           return getGraphFromDatabase(key);
         }

         public ListenableFuture<Graph> reload(final Key key, Graph prevGraph) {
           if (!needsRefresh(key,prevGraph)) {
             return Futures.immediateFuture(prevGraph);
           } else {
             // asynchronous!
             ListenableFutureTask<Graph> task = ListenableFutureTask.create(new Callable<Graph>() {
               public Graph call() {
                 return getGraphFromDatabase(key);
               }
             });
             executor.execute(task);
             return task;
           }
         }
       });

ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor();
ses.scheduleWithFixedDelay(
    new Runnable() {
        public void run() {
            for (Key key : graphs.asMap().keySet()) {
                graphs.refresh(key);
            }
        }
    }, 0, UPDATE_INTERVAL, TimeUnit.MINUTES);
Run Code Online (Sandbox Code Playgroud)

  • 如 https://code.google.com/p/guava-libraries/wiki/CachesExplained#Refresh 中所述,番石榴缓存重新加载本身确实会返回旧值,同时异步刷新缓存。`刷新与驱逐并不完全相同。正如 LoadingCache.refresh(K) 中指定的那样,刷新键会为键加载一个新值,可能是异步的。刷新键时仍会返回旧值(如果有),这与逐出相反,后者强制检索等待值重新加载。` (2认同)