首页 文章

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

提问于
浏览
44

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

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

更新:这是去年11月提交的关于缓存空值的JIRA问题,尚未解决:[#SPR-8871] @Cachable condition should allow referencing return value - Spring Projects Issue Tracker

3 回答

  • 3

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

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

  • 82

    update 这个答案现在已经过时了,对于Spring 3.2及以后看到Tech Trip的answer,OP:随意将其标记为已接受 .

    我没有't think that it'可能(尽管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();
    }
    
  • 2

    如果是Spring注释

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

    不起作用,你可以尝试:

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

    这个对我有用 .

相关问题