当前位置: 首页 > 知识库问答 >
问题:

@多个方法参数上的可缓存键

邵浩大
2023-03-14

从spring文档中:

@Cacheable(value="bookCache", key="isbn")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

如何指定@cacable使用isbncheckWarehouse作为键?

共有3个答案

淳于俊迈
2023-03-14

您可以使用Spring EL表达式,例如JDK 1.7上的表达式:

@Cacheable(value="bookCache", key="T(java.util.Objects).hash(#p0,#p1, #p2)")
沈翰
2023-03-14

在使用Spring3.2进行了一些有限的测试之后,似乎可以使用SpEL列表:{…,…,…} 。这也可以包括null值。Spring将列表作为键传递给实际的缓存实现。当使用Ehcache时,这类程序会在某个时候调用List#hashCode(),该程序会考虑到它的所有项。(我不确定Ehcache是否只依赖于哈希代码。)

我将其用于共享缓存,在该缓存中,我还将方法名包含在键中,而Spring默认键生成器不包含该方法名。这样我就可以轻松地擦除(单个)缓存,而不会(太多…)冒着为不同方法匹配密钥的风险。比如:

@Cacheable(value="bookCache", 
  key="{ #root.methodName, #isbn?.id, #checkWarehouse }")
public Book findBook(ISBN isbn, boolean checkWarehouse) 
...

@Cacheable(value="bookCache", 
  key="{ #root.methodName, #asin, #checkWarehouse }")
public Book findBookByAmazonId(String asin, boolean checkWarehouse)
...

当然,如果许多方法都需要此功能,并且您总是为密钥使用所有参数,那么还可以定义一个自定义密钥生成器,其中包括类和方法名称:

<cache:annotation-driven mode="..." key-generator="cacheKeyGenerator" />
<bean id="cacheKeyGenerator" class="net.example.cache.CacheKeyGenerator" />

...与:

public class CacheKeyGenerator 
  implements org.springframework.cache.interceptor.KeyGenerator {

    @Override
    public Object generate(final Object target, final Method method, 
      final Object... params) {

        final List<Object> key = new ArrayList<>();
        key.add(method.getDeclaringClass().getName());
        key.add(method.getName());

        for (final Object o : params) {
            key.add(o);
        }
        return key;
    }
}

易研
2023-03-14

更新:如果没有另外指定,当前的Spring缓存实现将使用所有方法参数作为缓存键。如果要使用选定的键,请参阅Arjan的答案,该答案使用SpEL list{isbn,#includeUsed},这是创建唯一键的最简单方法。

来自Spring文档

默认的密钥生成策略随着Spring 4.0的发布而改变。Spring的早期版本使用了一种密钥生成策略,对于多个密钥参数,只考虑参数的hashCode(),而不考虑equals();这可能会导致意外的密钥冲突(有关背景信息,请参阅SPR-10237)。新的“SimpleKeyGenerator”对此类场景使用复合键。

Spring4.0之前

我建议您将Spel表达式中的参数值与类似于key="#check Warehouse.toString()#isbn.toString()")的值进行协调,我相信这应该可以作为org.springframework.cache.interceptor.ExpressionEvalue ator返回对象,稍后将其用作键,因此不必在SPEL表达式中提供int

对于具有高冲突概率的哈希代码,您不能将其用作密钥。

该线程中有人建议使用T(java.util.Objects)。散列(#p0,#p1,#p2)但它不起作用,而且这种方法很容易破坏,例如,我使用了SPR-9377中的数据:

    System.out.println( Objects.hash("someisbn", new Integer(109), new Integer(434)));
    System.out.println( Objects.hash("someisbn", new Integer(110), new Integer(403)));

这两行打印-636517714在我的环境。

P. S.实际上在我们的参考留档里

@Cacheable(value="books", key="T(someType).hash(#isbn)") 
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

我认为这个例子是错误和误导,应该从留档中删除,因为键应该是唯一的。

P. P. S.还https://jira.springsource.org/browse/SPR-9036了解一些关于默认密钥生成的有趣想法。

为了正确起见,我想补充一点,作为一个有趣的数学/计算机科学事实,与内置哈希不同,使用安全的加密哈希函数(如MD5或SHA256),由于此类函数的属性,对于此任务来说是绝对可能的,但每次计算它可能太昂贵,查看Dan Boneh加密课程了解更多信息。

 类似资料:
  • http://docs.spring.io/spring/docs/current/spring-framework-reference/html/cache.html#cache-annotations-cacheable-key上面的链接显示了当一个方法的所有参数都不需要缓存键时如何指定一个键,缓存键是默认的。但是如何在可缓存注释中指定多个param(但不是方法参数列表中的全部)作为缓存的键呢

  • 问题内容: 从spring文档中: 如何指定使用和作为密钥? 问题答案: 如果没有另外指定,当前的Spring缓存实现将所有方法参数用作缓存键。如果要使用选定的键,请参考 Arjan的答案,该答案使用SpEL列表,这是创建唯一键的最简单方法。 从Spring文档 随着Spring 4.0的发布,默认的密钥生成策略发生了变化。Spring的早期版本使用密钥生成策略,该策略对于多个密钥参数仅考虑参数的

  • 我有一个Spring应用程序,它使用MyBatis进行持久化。我使用ehcache是因为速度对于这个应用程序很重要。我已经设置并配置了MyBatis和Ehcache。我使用一个名为“mybatis”的单一缓存,因为否则为每个实体创建单独的缓存将是荒谬的。 这是我的电子缓存。xml。 这是我的mybatis映射器界面的一个示例。 因为我有一个共享缓存,所以我需要一种方法使我的密钥对域对象是唯一的。作

  • 从块生成代码时,经常会发现需要多次使用子块的返回值。考虑一个值块,该值块查找并返回列表的最后一个元素。该块本身将有一个输入(一个列表),并返回一个值(最后一个元素)。这是JavaScript的生成器: var code = arg0 + '[' + arg0 + '.length - 1]'; 如果arg0是变量名,则此生成器返回完全可接受的JavaScript: aList[aList.leng

  • 我使用Spring缓存抽象,定义了多个缓存。有时,当数据更改时,我想逐出多个缓存。是否可以使用Spring的CacheExit注释逐出多个缓存?

  • 问题内容: 我想为一组SQL查询创建一个过滤器,以便用户最多可以通过三个值过滤SQL SELECT。用户界面具有三个文本框,每个文本框都将绑定到SQL表中的列名。用户可以通过这些文本框提供一个,两个或三个条件。 到目前为止,这就是我所拥有的。我知道这些声明将不起作用,但是我找不到解决该问题的方法。(使用不会返回任何结果。 问题答案: 如果我正确遵循,您想根据所有填充变量过滤结果,以处理未填充变量,