60

ホットデータをキャッシュするために 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;
            }
        });

私の問題は、データがデータベースに存在しない場合です。データを返しnullて、キャッシュを行わないようにしたいのです。しかし、グアバnullはキーをキャッシュに保存し、取得すると例外をスローします。

com.google.common.cache.CacheLoader$InvalidCacheLoadException: CacheLoader がキー shisoft に対して null を返しました。

null値のキャッシュを回避するにはどうすればよいですか?

4

5 に答える 5

83

ユーザーが見つからない場合は例外をスローし、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();
        }
    }
}

CacheLoader.load(K)Javadocから:

Returns:  
  the value associated with key; must not be null  
Throws:  
  Exception - if unable to load the result

null 値のキャッシュに関する疑問に答える:

このキャッシュ内のキーに関連付けられた値を返し、必要に応じて最初にその値をロードします。読み込みが完了するまで、このキャッシュに関連付けられた監視可能な状態は変更されません

( LoadingCache.get(K)Javadoc より)

例外をスローすると、ロードは完了したと見なされないため、新しい値はキャッシュされません。

編集

Guava キャッシュ 2.0 の一種であり、「Google Guava にインスパイアされた API を使用してメモリ内キャッシュを提供する」Caffeineでは、 methodから返すことができることnullloadに注意してください。

 Returns:
   the value associated with key or null if not found

移行を検討している場合、ユーザーが見つからない場合、データ ローダーは自由に戻ることができます。

于 2012-11-14T13:42:44.257 に答える
59

簡単な解決策: ascom.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());
            }
        });

編集: @Xaerxess の回答の方が優れていると思います。

于 2012-11-14T13:23:14.697 に答える
5

同じ問題に直面しました。ソースの欠損値が通常のワークフローの一部であったためです。getIfPresentgetおよび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;
    }
}
于 2017-01-04T06:58:25.297 に答える