我正在使用guava来缓存热数据.当缓存中不存在数据时,我必须从这样的数据库中获取它.
public final static LoadingCache<ObjectId, User> UID2UCache = CacheBuilder.newBuilder()
//.maximumSize(2000)
.weakKeys()
.weakValues()
.expireAfterAccess(10, TimeUnit.MINUTES)
.build(
new CacheLoader<ObjectId, User>() {
@Override
public User load(ObjectId k) throws Exception {
User u = DataLoader.datastore.find(User.class).field("_id").equal(k).get();
return u;
}
});
Run Code Online (Sandbox Code Playgroud)
我的问题是当数据在数据库中也不存在时,我宁愿返回null而不做任何缓存.但是guava只是在缓存中使用密钥保存null并在我得到它时抛出异常
com.google.common.cache.CacheLoader $ InvalidCacheLoadException:CacheLoader为key shisoft返回null.
那么,如何避免缓存空值?
Xae*_*ess 73
如果找不到用户,只需抛出一些异常,并在使用get(key)方法时在客户端代码中捕获它.
new CacheLoader<ObjectId, User>() {
@Override
public User load(ObjectId k) throws Exception {
User u = DataLoader.datastore.find(User.class).field("_id").equal(k).get();
if (u != null) {
return u;
} else {
throw new UserNotFoundException();
}
}
}
Run Code Online (Sandbox Code Playgroud)
来自CacheLoader.load(K)Javadoc:
Run Code Online (Sandbox Code Playgroud)Returns: the value associated with key; must not be null Throws: Exception - if unable to load the result
回答你对缓存空值的疑虑:
返回与此缓存中的键关联的值,必要时首先加载该值.在加载完成之前,不会修改与此高速缓存关联的可观察状态.
(来自LoadingCache.get(K)Javadoc)
如果抛出异常,则不认为load是完整的,因此不会缓存新值.
编辑:
请注意,在Caffeine中,这是一种Guava缓存2.0并"使用Google Guava启发的API提供内存缓存",您可以null从load方法返回:
Run Code Online (Sandbox Code Playgroud)Returns: the value associated with key or null if not found
如果您可以考虑迁移,那么当找不到用户时,您的数据加载器可以自由返回.
卢声远*_* Lu 51
简单的解决方案:使用com.google.common.base.Optional<User>而不是User作为值.
public final static LoadingCache<ObjectId, Optional<User>> UID2UCache = CacheBuilder.newBuilder()
...
.build(
new CacheLoader<ObjectId, Optional<User>>() {
@Override
public Optional<User> load(ObjectId k) throws Exception {
return Optional.fromNullable(DataLoader.datastore.find(User.class).field("_id").equal(k).get());
}
});
Run Code Online (Sandbox Code Playgroud)
编辑:我认为@Xaerxess的答案更好.
面临同样的问题,导致源中缺少值是正常工作流程的一部分。没有找到比自己使用getIfPresent,get和put方法编写一些代码更好的方法了。请参阅下面的方法,其中local是Cache<Object, Object>:
private <K, V> V getFromLocalCache(K key, Supplier<V> fallback) {
@SuppressWarnings("unchecked")
V s = (V) local.getIfPresent(key);
if (s != null) {
return s;
} else {
V value = fallback.get();
if (value != null) {
local.put(key, value);
}
return value;
}
}
Run Code Online (Sandbox Code Playgroud)