预加载番石榴缓存的值

Ric*_*ard 23 java caching guava

我有一个要求,我们从数据库加载静态数据以便在Java应用程序中使用.任何缓存机制都应具有以下功能:

  • 从数据库加载所有静态数据(加载后,此数据不会更改)
  • 从数据库加载新数据(启动时数据库中的数据不会改变,但可以添加新数据)

由于应用程序将部署到多个地理位置并且必须与单个数据库通信,因此不能延迟加载所有数据.延迟加载数据将使应用程序位于数据库的不同区域中对特定元素的第一个请求太慢.

我一直在Guava中使用MapMaker API成功,但我们现在正在升级到最新版本,我似乎无法在CacheBuilder API中找到相同的功能; 我似乎无法找到一种在启动时加载所有数据的简洁方法.

一种方法是从数据库加载所有密钥并单独通过Cache加载它们.这可以工作,但会导致对数据库的N + 1调用,这不是我正在寻找的有效解决方案.

public void loadData(){
    List<String> keys = getAllKeys();
    for(String s : keys)
        cache.get(s);
}
Run Code Online (Sandbox Code Playgroud)

或者另一个解决方案是使用ConcurrentHashMap实现并自己处理所有线程和缺少的条目?我并不热衷于这样做,因为MapMaker和CacheBuilder API免费提供基于密钥的线程锁定,而无需提供额外的测试.我也很确定MapMaker/CacheBuilder实现会有一些我不知道/没有时间调查的效率.

public Element get(String key){
    Lock lock = getObjectLock(key);
    lock.lock();
    try{
        Element ret = map.get(key)
        if(ret == null){
            ret = getElement(key); // database call
            map.put(key, e);
        }
        return ret;
    }finally {
        lock.unlock();
    } 
}
Run Code Online (Sandbox Code Playgroud)

谁能想到更好的解决方案来满足我的两个要求?


功能要求

我不认为预加载缓存是一种不常见的要求,因此如果CacheBuilder提供了预加载缓存的配置选项,那将会很好.我认为提供一个接口(很像CacheLoader),它将在启动时填充缓存,这将是一个理想的解决方案,例如:

CacheBuilder.newBuilder().populate(new CachePopulator<String, Element>(){

    @Override
    public Map<String, Element> populate() throws Exception {
        return getAllElements();
    }

}).build(new CacheLoader<String, Element>(){

    @Override
    public Element load(String key) throws Exception {       
        return getElement(key);
    }

});
Run Code Online (Sandbox Code Playgroud)

此实现将允许使用所有相关的Element对象预先填充Cache,同时保持底层CustomConcurrentHashMap对外部世界不可见.

小智 7

在短期内我会使用Cache.asMap().putAll(Map<K, V>).

一旦发布了Guava 11.0,您就可以使用Cache.getAll(Iterable<K>),它将为所有缺席元素发出一个批量请求.

  • Cache.getAll(Iterable <K>)不会为缺少的元素发出单个批量请求.根据API,它将为所提供的所有密钥发出一次调用,除非重写.有关此问题的讨论,请参阅http://code.google.com/p/guava-libraries/issues/detail?can=2&q=775&colspec=ID%20Type%20Status%20Milestone%20Summary&id=775 (11认同)

Eti*_*veu 4

我将从数据库加载所有静态数据,并使用cache.asMap().put(key, value)([Guava 10.0.1 允许在 Cache.asMap() 视图上进行写入操作][1])将其存储在缓存中。

当然,如果您的缓存配置为逐出条目,则此静态数据可能会被逐出......

CachePopulator 的想法很有趣。

  • 哇。这是我们的第一个补丁版本,但我认为补丁版本的真正概念是很容易证明升级的合理性,因为它可以进行的更改非常有限。 (4认同)
  • 好吧,10.0.1 是一个小错误修复版本,其目标是重新允许cache.asMap().put()。如果你不能做这么小的升级,我猜你现在就完蛋了...... (3认同)