Guava Cache是Google開源的Java工具集庫Guava裏的一款緩存工具,一直以爲使用起來比較簡單,沒想到此次竟然還踩了一個坑git
功能需求抽象出來很簡單,就是將數據庫的查詢sthMapper.findById(Long id)
的結果緩存起來。但同時還有批量請求,爲了提升效率,確定要批量查詢數據庫,sthMapper.findByIds(Collection<Long> ids)
github
對於的guava cache 處理類數據庫
// 定義guava緩存
public SthCache() {
sthCache = CacheBuilder.newBuilder()
.maximumSize(SIZE)
.refreshAfterWrite(3, TimeUnit.SECONDS)
.build(new CacheLoader<Long, List<Long>>() {
@Override
public List<Long> load(final Long id) {
return doLoad(Arrays.asList(id)).get(id);
}
@Override
public Map<Long, List<Long>> loadAll(
final Iterable<? extends Long> ids)
throws Exception {
return doLoad(Lists.newArrayList(ids));
}
});
}
// 實際從數據庫中加載數據
private Map<Long, List<Long>> doLoad(final List<Long> ids) {
return sthMapper.findByIds(ids);
}
// 批量獲取數據
public Map<Long, List<Long>> getSthById(final List<Long> ids) {
return sthCache.getAll(ids);
}
複製代碼
沒毛病,getAll(Iterable<? extendsK>)方法用來執行批量查詢。默認狀況下,對每一個不在緩存中的鍵,getAll方法會單獨調用CacheLoader.load來加載緩存項。若是批量的加載比多個單獨加載更高效,你能夠重載CacheLoader.loadAll來利用這一點。getAll(Iterable)的性能也會相應提高。這邊定義了loadAll效率高了。緩存
在debug的時候發現確實走的loadAll,批量查詢數據庫。可是上線後,線上監控數據卻發現這個接口耗時很長,經過分析,發現有不少sthMappper.findByIds()的單個查詢。也就是說,並無調用loadAll
,走到批量查詢數據庫中。bash
ImmutableMap<K, V> getAll(Iterable<? extends K> keys) throws ExecutionException {
int hits = 0;
int misses = 0;
// 省略一大坨
try {
if (!keysToLoad.isEmpty()) {
try {
// 調用loadAll
Map<K, V> newEntries = loadAll(keysToLoad, defaultLoader);
複製代碼
批量查詢時,對於沒有命中的,確實調用的loadAll來加載數據的。app
那問題就不是這邊了。在load()
方法打了個斷點,緣由就找到了。ide
原來是refesh的時候,加載的。refreshAfterWrite
刷新緩存數據時調用的仍是load方法。工具
搜索了下,github.com/google/guav… github上這個issue還在。汗!!!性能
最後我這邊解決是用Spring Cache
統一了緩存管理。ui
對於開源庫的使用不可只知其然,不知其因此然。
關注公衆號【方丈的寺院】,第一時間收到文章的更新,與方丈一塊兒開始技術修行之路