前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >guava缓存批量获取的一个坑

guava缓存批量获取的一个坑

作者头像
方丈的寺院
修改2019-10-17 18:00:12
1.2K0
修改2019-10-17 18:00:12
举报
文章被收录于专栏:方丈的寺院方丈的寺院

摘要

Guava Cache是Google开源的Java工具集库Guava里的一款缓存工具,一直觉得使用起来比较简单,没想到这次居然还踩了一个坑。

背景

功能需求抽象出来很简单,就是将数据库的查询 sthMapper.findById(Longid)的结果缓存起来。但同时还有批量请求,为了提高效率,肯定要批量查询数据库, sthMapper.findByIds(Collection<Long>ids)

对于的guava cache 处理类

代码语言:javascript
复制
 // 定义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);
 }

问题

在debug的时候发现确实走的loadAll,批量查询数据库。但是上线后,线上监控数据却发现这个接口耗时很长,通过分析,发现有很多sthMappper.findByIds()的单个id查询。也就是说,并没有调用 loadAll,走到批量查询数据库中。

分析解决

  1. 首先看了下guava的代码实现 ImmutableMap<K,V>getAll(Iterable<?extendsK>keys)throwsExecutionException{inthits=0;intmisses=0;// 省略一大坨 try { if (!keysToLoad.isEmpty()) { try { // 调用loadAll Map<K, V> newEntries = loadAll(keysToLoad, defaultLoader);

批量查询时,对于没有命中的,确实调用的loadAll来加载数据的。

那问题就不是这边了。在 load()方法打了个断点,原因就找到了。

原来是refesh的时候加载的。refreshAfterWrite 刷新缓存数据时调用的还是load方法。

搜索了下,https://github.com/google/guava/issues/1975 github上这个issue还在。汗!!!

最后我这边解决是用 SpringCache统一了缓存管理。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-10-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 方丈的寺院 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 摘要
  • 背景
  • 问题
  • 分析解决
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档