我正在使用Google Guava库进行缓存。 对于自动缓存刷新,我们可以执行以下操作:
cache = CacheBuilder.newBuilder()
.refreshAfterWrite(15, TimeUnit.MINUTES)
.maximumSize(100)
.build(....);
但是,当第一个条目的陈旧请求发生时,会执行自动刷新。
有没有办法自动刷新它,即使没有请求缓存数据?像每15分钟一样,缓存数据应该从Db中提取并加载它,无论是否有人称为缓存数据与否。
此外,Guava的缓存到期时间适用于整个缓存。 是否可以基于密钥使缓存值失效?类似缓存数据,密钥“NOT_SO_FREQ_CHANGE_DATA”每1小时到期,密钥“FREQ_CHANGING_DATA”的数据应该每15分钟到期一次?
答案 0 :(得分:25)
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);
}
但在这种情况下,您可能希望覆盖CacheBuilder.reload(K, V)
中的MyCacheLoader
方法,以便它以异步方式执行。
关于第二个问题,不,你不能在番石榴中设置每个条目的到期日。
答案 1 :(得分: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);
答案 2 :(得分:5)
带并行流的JAVA 8版本:
Executors
.newSingleThreadScheduledExecutor()
.scheduleWithFixedDelay(() -> configurationCache
.asMap()
.keySet()
.parallelStream()
.forEach((key) -> configurationCache.refresh(key)),
0,
1, TimeUnit.SECONDS);
答案 3 :(得分:1)
是否可以使用下面的代码片段自动重载缓存值,而无需调用刷新方法?
cacher =
CacheBuilder.newBuilder()
.refreshAfterWrite(10, TimeUnit.SECONDS)
.build(CacheLoader.asyncReloading(new CacheLoader<String, String>() {
@Override
public String load(String key) throws Exception {
return method-call();
}
}, Executors.newSingleThreadExecutor()));
答案 4 :(得分:-1)
以下是一些刷新缓存的示例代码。番石榴缓存易于实现,而且速度快。
import java.util.concurrent.ExecutionException
import java.util.concurrent.TimeUnit;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
public class GuavaTest {
private static GuavaTest INSTANCE = new GuavaTest();
public static GuavaTest getInstance(){
return INSTANCE;
}
private LoadingCache<String,String> cache;
private GuavaTest() {
cache = CacheBuilder.newBuilder()
.refreshAfterWrite(2,TimeUnit.SECONDS)
.build(new CacheLoader<String, String>() {
@Override
public String load(String arg0) throws Exception {
return addCache(arg0);
}
});
}
private String addCache(String arg0) {
System.out.println("Adding Cache");
return arg0.toUpperCase();
}
public String getEntry(String args) throws ExecutionException{
System.out.println(cache.size());
return cache.get(args);
}
public static void main(String[] args) {
GuavaTest gt = GuavaTest.getInstance();
try {
System.out.println(gt.getEntry("java"));
System.out.println(gt.getEntry("java"));
Thread.sleep(2100);
System.out.println(gt.getEntry("java"));
System.out.println(gt.getEntry("java"));
} catch (ExecutionException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
我参考了这篇文章guava cache example