项目背景
- 最近在做一个给帖子配图的项目,我这里只负责配图,上游将帖子的id发给我,我拿着帖子id去另一个服务查询,但我不能每次都去查人家的服务啊,所以我将每次查到的数据添加到缓存中了.
- 帖子会有过期的时间,我的上游可能还没收到帖子过期的消息就已经将帖子id发给我了,这时我也需要拿着帖子id去查帖子服务,查不到时我这里就拿到null了,我把查询的结果放到缓存中,当get的时候不就报错了嘛!
private static Cache<String, RawData> tenMiniCache =
CacheBuilder.newBuilder()
// 设置缓存初始大小,应该合理设置,后续会扩容
.initialCapacity(100000)
// 最大值
.maximumSize(400000)
// 并发数设置
.concurrencyLevel(10)
.expireAfterWrite(10, TimeUnit.MINUTES)
// 统计缓存命中率
.recordStats()
.build();
RawData contentWtable = null;
try {
contentWtable =
tenMiniCache.get(
ITEMKEY + itemId,
() -> {
RawData contentWtableInfo = null;
try {
contentWtableInfo = speedContentService.getContentWtable(itemId, 1);
logger.info(
"speedContentService getContentWtable cost:"
+ TimeUtils.diffMs(startTime)
+ "-info:"
+ JSON.toJSONString(
contentWtableInfo,
SerializerFeature.DisableCircularReferenceDetect));
} catch (Exception e) {
logger.error(
"featch contentWtable from speedContentService failed,params:"
+ itemId
+ "-reason:",
e);
}
return contentWtableInfo;
});
} catch (ExecutionException e) {
logger.error(
"featch contentWtable from cache failed,params:" + itemId + "-reason:", e);
return item;
}
看这段代码,如果我拿到了null直接顺带存到缓存中,此时就会不停的报错了…
解决方案
- 那么话又说回来,出了bug就赶紧解决吧,如何解决呢?就需要用到Optional了
- 建造的cache如下
private static Cache<String, Optional<RawData>> tenMiniCache =
CacheBuilder.newBuilder()
// 设置缓存初始大小,应该合理设置,后续会扩容
.initialCapacity(10)
// 最大值
.maximumSize(100)
// 并发数设置
.concurrencyLevel(10)
// 缓存过期时间,写入后1小时 过期
.expireAfterWrite(10, TimeUnit.MINUTES)
// 统计缓存命中率
.recordStats()
.build();
- 在功能处实现如下
Optional<RawData> rawDataOptional = null;
try {
rawDataOptional =
BaseCacheUtil.getTenMiniCache()
.get(
itemId,
() -> {
RawData contentWtable = null;
contentWtable = speedContentService.getContentWtable(itemId, 1);
logger.info(
"speedContentService getContentWtable cost:"
+ TimeUtils.diffMs(startTime)
+ "-info:"
+ JSON.toJSONString(
contentWtable,
SerializerFeature.DisableCircularReferenceDetect));
return Optional.ofNullable(contentWtable);
});
} catch (ExecutionException e) {
logger.error("get contentWtable from cache is failed!itemId is"+ itemId +"the reason is:", e);
return item;
}
if (!rawDataOptional.isPresent()) {
logger.info("get contentWtable from cache is null,by itemId:" + itemId);
return item;
}