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

新手上路,请多包涵

有没有一种方法可以指定如果该方法返回空值,则不要将结果缓存在 @Cacheable 注释中,以便像这样的方法?

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

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

原文由 David Zhao 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1k
2 个回答

万岁,从 Spring 3.2 开始,框架允许使用 Spring SPEL 和 unless 。来自 Cacheable 周围的 java 文档的注释:

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

公共抽象字符串除非

用于否决方法缓存的 Spring 表达式语言 (SpEL) 属性。

与 condition() 不同,此表达式在调用方法后进行计算,因此可以引用结果。默认为“”,意味着永远不会否决缓存。

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

所以在上面的例子中,你可以简单地注释如下(#result 可用于测试方法的返回值):

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

我想这种情况是由于使用可插入缓存实现(例如允许缓存空值的 Ehcache)引起的。根据您的用例场景,这可能是可取的,也可能不是可取的。

原文由 TechTrip 发布,翻译遵循 CC BY-SA 4.0 许可协议

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

我不认为这是可能的(即使在使用 @CacheEvict 参数 beforeInvocation 设置为 false,这是默认值的方法调用之后可以执行的 Spring 中有条件缓存驱逐)检查 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();
}

原文由 Boris Treukhov 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏