update unless implementations ejemplo cacheevict cacheable cache spring caching memcached

unless - ¿Cómo le digo a Spring Cache que no almacene el valor nulo en @Cacheable Anotación



spring cacheable key (3)

Hooray, a partir de Spring 3.2 el marco permite esto usando Spring SPEL y a unless . Nota del doc de java que rodea a Cacheable:

http://static.springsource.org/spring/docs/3.2.x/javadoc-api/org/springframework/cache/annotation/Cacheable.html

cadena abstracta pública a menos que

El atributo de lengua de expresión de primavera (SpEL) se usa para vetar el almacenamiento en caché de métodos.

A diferencia de la condición (), esta expresión se evalúa después de haber llamado al método y, por lo tanto, puede referirse al resultado. El valor predeterminado es "", lo que significa que el almacenamiento en caché nunca se veta.

El aspecto importante es que a unless que se evalúe después de que se haya llamado al método. Esto tiene mucho sentido porque el método nunca se ejecutará si la clave ya está en la memoria caché.

Entonces, en el ejemplo anterior simplemente anotarías de la siguiente manera (# resultado está disponible para probar el valor de retorno de un método):

@Cacheable(value="defaultCache", key="#pk", unless="#result == null") public Person findPerson(int pk) { return getSession.getPerson(pk); }

Me imagino que esta condición se debe al uso de implementaciones de caché conectables como Ehcache, que permite el almacenamiento en caché de valores nulos. Dependiendo de su escenario de caso de uso, esto puede o no ser deseable.

¿Hay alguna forma de especificar que si el método arroja un valor nulo, entonces no almacene en caché el resultado en la anotación @Cacheable para un método como este?

@Cacheable(value="defaultCache", key="#pk") public Person findPerson(int pk) { return getSession.getPerson(pk); }

Actualización: aquí está el problema de JIRA presentado con respecto al valor nulo de almacenamiento en caché en noviembre pasado, que aún no se ha resuelto: [# SPR-8871] @La condición de caché debe permitir hacer referencia al valor de retorno - Spring Projects Issue Tracker


Si la anotación de primavera

@Cacheable(value="defaultCache", key="#pk",unless="#result!=null")

no funciona, puedes intentar:

@CachePut(value="defaultCache", key="#pk",unless="#result==null")

Esto funciona para mi.


Actualice que esta respuesta no está actualizada, para Spring 3.2 y posterior vea la answer Tech Trip, OP: no dude en marcarla como aceptada.

No creo que sea posible (aunque exista el desalojo de caché condicional en Spring que se puede ejecutar después de la invocación del método con el parámetro @CacheEvict beforeInvocation establecido en false, que es el valor predeterminado) examinar la clase CacheAspectSupport muestra que el valor devuelto no es almacenado en cualquier lugar antes de inspectAfterCacheEvicts(ops.get(EVICT)); llamada.

protected Object execute(Invoker invoker, Object target, Method method, Object[] args) { // check whether aspect is enabled // to cope with cases where the AJ is pulled in automatically if (!this.initialized) { return invoker.invoke(); } // get backing class Class<?> targetClass = AopProxyUtils.ultimateTargetClass(target); if (targetClass == null && target != null) { targetClass = target.getClass(); } final Collection<CacheOperation> cacheOp = getCacheOperationSource().getCacheOperations(method, targetClass); // analyze caching information if (!CollectionUtils.isEmpty(cacheOp)) { Map<String, Collection<CacheOperationContext>> ops = createOperationContext(cacheOp, method, args, target, targetClass); // start with evictions inspectBeforeCacheEvicts(ops.get(EVICT)); // follow up with cacheable CacheStatus status = inspectCacheables(ops.get(CACHEABLE)); Object retVal = null; Map<CacheOperationContext, Object> updates = inspectCacheUpdates(ops.get(UPDATE)); if (status != null) { if (status.updateRequired) { updates.putAll(status.cUpdates); } // return cached object else { return status.retVal; } } retVal = invoker.invoke(); inspectAfterCacheEvicts(ops.get(EVICT)); if (!updates.isEmpty()) { update(updates, retVal); } return retVal; } return invoker.invoke(); }