¿Cómo evitar el almacenamiento en caché cuando los valores son null?


Estoy usando guayaba para almacenar datos en caché.Cuando los datos no existen en la caché, tengo que obtenerlos de la base de datos de esta manera.

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

Mi problema es que cuando los datos tampoco existen en la base de datos, prefiero devolver null y no hacer ningún almacenamiento en caché. Pero guava simplemente guardar null con clave en la caché y lanzar excepción cuando lo consigo

Com.Google.común.cache.CacheLoader Inval InvalidCacheLoadException: CacheLoader devolvió null para la clave shisoft.

Entonces, cómo ¿evitar el almacenamiento en caché de valores nulos?

Author: Shisoft, 2012-11-14

4 answers

Basta con lanzar alguna excepción si el usuario no se encuentra y atraparlo en el código del cliente mientras se usa get(key) método.

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

Desde CacheLoader.load(K) Javadoc:

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

Respondiendo a sus dudas sobre el almacenamiento en caché de valores nulos:

Devuelve el valor asociado a key en esta caché, primero cargando ese valor si es necesario. Ningún estado observable asociado con esto la caché se modifica hasta que se complete la carga .

(desde LoadingCache.get(K) Javadoc)

Si lanza una excepción, load no se considera completa, por lo que no se almacena ningún valor nuevo en caché.

EDIT :

Tenga en cuenta que en Caffeine , que es una especie de Guava cache 2.0 y "proporciona una caché en memoria utilizando una API inspirada en Google Guava" puede devolver null desde load método :

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

Si puede considerar la migración, su cargador de datos podría regresar libremente cuando el usuario no esté encontrar.

 64
Author: Xaerxess,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-11 07:25:49

Solución simple: use com.google.common.base.Optional<User> en lugar de User como valor.

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

EDITAR: Creo que la respuesta de @Xaerxess es mejor.

 44
Author: 卢声远 Shengyuan Lu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-14 14:17:13

Se enfrentó al mismo problema, porque los valores faltantes en el origen formaban parte del flujo de trabajo normal. No he encontrado nada mejor que escribir algún código yo mismo usando getIfPresent, get y put métodos. Véase el método a continuación, donde local es 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;
    }
}
 2
Author: Raman Yelianevich,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-04 06:58:25

Cuando desee almacenar en caché algunos valores NULL, podría usar otro pentagrama que se comporte como NULL.

Y antes de dar la solución, le sugeriría que no exponga LoadingCache al exterior. En su lugar, debe usar el método para restringir el alcance de la caché.

Por ejemplo, podría usar LoadingCache<ObjectId, List<User>> como tipo de retorno. Y luego, podría devolver una lista vacía cuando pudiera recuperar valores de la base de datos. Puedes usar -1 como valor Entero o Long NULL, puedes usar "" como Cadena Valor NULL, y así sucesivamente. Después de esto, debe proporcionar un método para manejar el valor NULO.

when(value equals NULL(-1|"")){
   return null;
}
 0
Author: jayxhj,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-08 10:22:03