如何告诉Spring缓存不要在@Cacheable注释中缓存空值

Dav*_*hao 60 spring memcached caching

有没有办法指定如果方法返回null值,那么不要将结果缓存在这样的方法的@Cacheable注释中?

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

更新:以下是去年11月提交的关于缓存空值的JIRA问题,尚未解决: [#SPR-8871] @Cachable条件应该允许引用返回值 - Spring Projects问题跟踪器

Tec*_*rip 107

Hooray,从Spring 3.2开始,框架允许使用Spring SPEL和unless.关于Cacheable的java doc中的注意事项:

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

public abstract String除非

Spring Expression Language(SpEL)属性用于否决方法缓存.

与condition()不同,此表达式在调用方法后进行计算,因此可以引用结果.默认为"",表示缓存永远不会被否决.

重要的方面是unless在调用方法后进行评估.这非常有意义,因为如果密钥已经在缓存中,则永远不会执行该方法.

因此,在上面的示例中,您只需注释如下(#result可用于测试方法的返回值):

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

我想这种情况源于使用可插入缓存实现,如Ehcache,它允许缓存空值.根据您的使用案例情况,这可能是也可能不是.


Bor*_*hov 5

更新此答案现在已过时,对于Spring 3.2和更高版本,请参阅Tech Trip的答案,OP:随时将其标记为已接受。

我认为这是不可能的(即使在Spring中有条件的Cache驱逐可以在将@CacheEvict参数beforeInvocation设置为false(这是默认值)的方法调用之后可以执行)检查CacheAspectSupport类表明返回的值未存储在之前的inspectAfterCacheEvicts(ops.get(EVICT));通话。

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();
}
Run Code Online (Sandbox Code Playgroud)


小智 5

如果Spring注解

@Cacheable(value="defaultCache", key="#pk",unless="#result!=null")
Run Code Online (Sandbox Code Playgroud)

不起作用,你可以尝试:

@CachePut(value="defaultCache", key="#pk",unless="#result==null")
Run Code Online (Sandbox Code Playgroud)

这个对我有用。

  • _缓存,除非结果!= null_意味着_缓存,如果结果== null_。因此,正确的表达式是`unless="#result==null"`,这意味着_Cache except result == null_,这意味着_Cache if result != null_。 (18认同)
  • 您的意思是“unless="#result == null"”吗? (13认同)