预加载番石榴缓存的值
我有一个要求,我们从数据库加载静态数据以便在Java应用程序中使用。 任何缓存机制都应具有以下function:
- 从数据库加载所有静态数据(加载后,此数据不会更改)
- 从数据库加载新数据(启动时数据库中的数据不会改变,但可以添加新数据)
延迟加载所有数据不是一种选择,因为应用程序将部署到多个地理位置,并且必须与单个数据库通信。 如果应用程序位于与数据库不同的区域,则延迟加载数据将使对特定元素的第一个请求太慢。
我一直在使用Guava中的MapMaker API成功但我们现在正在升级到最新版本,我似乎无法在CacheBuilder API中找到相同的function; 我似乎无法找到一种在启动时加载所有数据的简洁方法。
一种方法是从数据库加载所有密钥并分别通过缓存加载。 这可以工作,但会导致对数据库的N + 1调用,这不是我正在寻找的有效解决方案。
public void loadData(){ List keys = getAllKeys(); for(String s : keys) cache.get(s); }
或者另一个解决方案是使用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(); } }
谁能想到更好的解决方案来满足我的两个要求?
function要求
我不认为预加载缓存是一种不常见的要求,因此如果CacheBuilder提供了一个预加载缓存的配置选项,那就太好了。 我认为提供一个接口(很像CacheLoader),它将在启动时填充缓存,这将是一个理想的解决方案,例如:
CacheBuilder.newBuilder().populate(new CachePopulator(){ @Override public Map populate() throws Exception { return getAllElements(); } }).build(new CacheLoader(){ @Override public Element load(String key) throws Exception { return getElement(key); } });
此实现将允许使用所有相关的Element对象预先填充Cache,同时保持底层CustomConcurrentHashMap对外部世界不可见。
在短期内我会使用Cache.asMap().putAll(Map
。
一旦发布了Guava 11.0,您就可以使用Cache.getAll(Iterable
,它将为所有缺席元素发出单个批量请求。
我将从DB加载所有静态数据,并使用cache.asMap().put(key, value)
将其存储在Cache中cache.asMap().put(key, value)
([Guava 10.0.1允许在Cache.asMap()视图上执行写操作] [1 ])。
当然,如果您的缓存配置为逐出条目,这些静态数据可能会被驱逐……
CachePopulator的想法很有趣。
- Java – 使用大量RAM的GUI时钟?
- 使JTable单元格编辑器值可选,但不可编辑?
- ClassCastException无法将数据源强制转换为javax.sql.ConnectionPoolDataSource
- 指向Java LinkedList节点的指针
- 无法使用mockito模拟私有方法
- HTTPSURLconnection和Apache(系统)DefaultHttpClient之间的证书链不同
- 是RC4还是ARCFOUR? 使用SecretKeySpec时出现InvalidKeyException?
- Java – 在排序数组中查找最不常见的整数
- 使用Eclipse在Manifest文件中构建ClassPath变量