Comment éviter la mise en cache lorsque les valeurs sont nulles?

j'utilise la goyave pour cacher des données chaudes.Quand les données n'existent pas dans le cache,je dois les récupérer dans une base de données comme celle-ci.

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;
            }
        });

mon problème est que lorsque les données n'existent pas dans la base de données non plus, je préfère retourner null et ne pas faire de mise en cache. Mais guava juste enregistrer null avec la clé dans le cache et jeter l'exception quand je l'obtiens

com.Google.commun.cache.CacheLoader $ InvalidCacheLoadException: CacheLoader retourné null pour la clé shisoft.

alors, comment éviter la mise en cache des valeurs nulles?

45
demandé sur Shisoft 2012-11-14 16:45:12

4 réponses

il suffit de lancer une Exception si l'utilisateur n'est pas trouvé et l'attraper dans le code client en utilisant get(key) méthode.

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

répondre à vos doutes sur la mise en cache des valeurs nulles:

renvoie la valeur associée à la clé dans ce cache, premier chargement cette valeur, si nécessaire. pas d'état observable associé à ce le cache est modifié jusqu'à chargement terminé.

(LoadingCache.get(K) Javadoc)

si vous lancez une exception, la charge n'est pas considérée comme complète, donc aucune nouvelle valeur n'est mise en cache.

EDIT:

Notez que dans la Caféine, qui est une sorte de cache Goyave 2.0 et "fournit une cache en mémoire à l'aide D'une API Google Goyave inspiré" vous retour nullload méthode:

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

si vous envisagez de migrer, votre chargeur de données pourrait librement revenir lorsque l'utilisateur n'est pas trouvé.

64
répondu Xaerxess 2018-05-11 07:25:49

solution Simple: utiliser com.google.common.base.Optional<User> au lieu de User en tant que valeur.

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());
            }
        });

EDIT: je pense que la réponse de @Xaerxess est meilleure.

44
répondu 卢声远 Shengyuan Lu 2012-11-14 14:17:13

fait face au même problème, parce que les valeurs manquantes dans la source faisait partie du flux de travail normal. Je n'ai rien trouvé de mieux que d'écrire du code moi-même en utilisant getIfPresent,get et put méthodes. Voir la méthode ci-dessous, où localCache<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;
    }
}
2
répondu Raman Yelianevich 2017-01-04 06:58:25

lorsque vous voulez mettre en cache des valeurs NULL, vous pouvez utiliser d'autres portées qui se comportent comme NULL.

et avant de donner la solution, je vous suggérerais de ne pas exposer LoadingCache à l'extérieur. Vous devriez plutôt utiliser la méthode pour restreindre la portée du Cache.

Par exemple, vous pouvez utiliser LoadingCache<ObjectId, List<User>> comme type de retour. Et puis, vous pourriez retourner la liste vide quand vous pourriez ' N récupérer des valeurs de la base de données. Vous pouvez utiliser -1 Comme entier ou Long NULL valeur, vous pourrait utiliser "" comme chaîne de caractères NULL valeur, et ainsi de suite. Après cela, vous devriez fournir une méthode pour handler la valeur nulle.

when(value equals NULL(-1|"")){
   return null;
}
0
répondu jayxhj 2018-08-08 10:22:03