java 带有项目/实体集合的 Spring Cache

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/44529029/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 08:13:45  来源:igfitidea点击:

Spring Cache with collection of items/entities

javaspringspring-cache

提问by Charbel

I am using Spring Cache, where I pass in a collection of keys, and the return is a list of entities. I would like to have the caching framework understand that each element in the return list is to be cached with the corresponding code. At the moment, it seems that the key is the whole list, and if I am missing a key in the subsequent call, it'll try to reload the whole collection again.

我正在使用 Spring Cache,我在其中传递了一组键,返回的是一个实体列表。我想让缓存框架理解返回列表中的每个元素都将与相应的代码一起缓存。目前,似乎关键是整个列表,如果我在后续调用中遗漏了一个关键,它会再次尝试重新加载整个集合。

@Override
@Cacheable(value = "countries")
public List<Country> getAll(List<String>codes) {
    return countryDao.findAllInCodes(codes);
}

another possibility is that the return is a map, similarly I would like the cache to be intelligent enough to only query for items that were never queried before, also to cache them each item with its key.

另一种可能性是返回是一个映射,同样我希望缓存足够智能,以便仅查询以前从未查询过的项目,也可以使用其键缓存每个项目。

@Override
@Cacheable(value = "countries")
public Map<String,Country> getAllByCode(List<String>codes) {
    return countryDao.findAllInCodes(codes);
}

Suppose the country class looks like this:

假设 country 类如下所示:

class Country{
  String code; 
  String fullName;
  long id;

... // getters setters constructurs etc.. 
}

Is this possible with Spring Cache?

Spring Cache 可以做到这一点吗?

回答by John Blum

In fact, it is possible, even with Spring's Caching Abstraction, but not out-of-the-box (OOTB). Essentially, you must customize Spring'scaching infrastructure (Explained further below)

事实上,即使使用Spring 的 Caching Abstraction也是可能,但不是开箱即用的 (OOTB)。本质上,您必须自定义Spring 的缓存基础结构(下面进一步解释)

By default, Spring'scaching infrastructure uses the entire @Cacheablemethod parameter arguments as the cache "key", as explained here. Of course you can also customize the key resolution using either a SpEL Expressionor with a custom KeyGeneratorimplementation, as explained here.

通过默认情况下Spring的缓存架构采用全@Cacheable方法参数的参数作为缓存的“钥匙”,作为解释在这里。当然,你也可以自定义使用一个关键分辨率规划环境地政司表达或用自定义KeyGenerator实现,如解释在这里

Still, that does notbreak up the collection or array of parameter argumentsalong with the @Cacheablemethod's return valueinto individual cache entries (i.e. key/value pairs based on the array/collection or Map).

尽管如此,这不会参数参数的集合或数组以及@Cacheable方法的返回值分解为单独的缓存条目(即基于数组/集合或 Map 的键/值对)。

For that, you need a custom implementation of Spring'sCacheManager(dependent on your caching strategy/provider) and Cacheinterfaces.

为此,您需要Spring 的自定义实现CacheManager(取决于您的缓存策略/提供程序)和Cache接口。

NOTE: Ironically, this will be the 3rd time I have answered nearly the same question, first here, then hereand now here, :-). Anyway...

注意:具有讽刺意味的是,这将是我第三次回答几乎相同的问题,首先是这里,然后是这里,现在是这里,:-)。反正...

I have updated/cleaned up my example(a bit) for this posting.

我已经为这篇文章更新/清理了我的例子(一点)。

Notice that my example extends and customizesthe ConcurrentMapCacheManagerprovided in the Spring Frameworkitself.

请注意,我的例子扩展和定制ConcurrentMapCacheManager所提供的Spring框架本身。

Theoretically, you could extend/customize any CacheManagerimplementation, like Redis'sin Spring Data Redis, here(source), or Pivotal GemFire'sCacheManagerin Spring Data GemFire, here(source). The open source version of Pivotal GemFireis Apache Geode, which has a corresponding Spring Data Geodeproject, (source for CacheManagerin Spring Data Geode, which is basically identical to SD GemFire). Of course, you can apply this technique to other caching providers... Hazelcast, Ehcache, etc.

从理论上说,你可以扩展/自定义任何CacheManager的实现,像Redis的公司春季Redis的数据这里),或枢纽的GemFire的CacheManager春季数据的GemFire这里)。的开源版本匹的GemFire阿帕奇的Geode,其具有相应的弹簧数据的Geode项目,(来源的CacheManager春季数据的Geode,这基本上等同于SD的GemFire)。当然,你可以将此技术应用到其他缓存提供者...... Hazelcast、Ehcache 等。

However, the real guts of the work is handled by the custom implementation(or mores specifically, the base class) of Spring'sCacheinterface.

然而,真正的工作是由Spring 的Cache接口的自定义实现(或更具体地说,基类)处理

Anyway, hopefully from my example, you will be able to figure out what you need to do in your application to satisfy your application's caching requirements.

无论如何,希望从我的示例中,您将能够弄清楚您需要在应用程序中做什么才能满足应用程序的缓存要求。

Additionally, you can apply the same approach to handling Maps, but I will leave that as an exercise for you, ;-).

此外,您可以应用相同的方法来处理Maps,但我会将其作为练习留给您,;-)。

Hope this helps!

希望这可以帮助!

Cheers, John

干杯,约翰

回答by Peter Szanto

With @CachePut and a helper method you can achieve it very simply like this :

使用@CachePut 和辅助方法,您可以像这样非常简单地实现它:

public List<Country> getAllByCode(List<String>codes) {
    return countryDao.findAllInCodes(codes);
}

public void preloadCache(List<String>codes) {
    Map<String,Country> allCountries = getAllByCode(codes);
    for (Country country : allCountries) {
        cacheCountry(country);
    }
}

@CachePut
public Country cacheCountry(Country country) {
    return country
}

Note

笔记

This will only add values to the cache, but never remove old values. You can easily do cache eviction before you add new values

这只会向缓存添加值,但不会删除旧值。在添加新值之前,您可以轻松地进行缓存逐出

Option 2

选项 2

There is a proposal to make it work like this :

有一个建议让它像这样工作:

@CollectionCacheable
public List<Country> getAllByCode(List<String>codes) {    

See :

看 :

If you are impatient take the code from GitHub and integrate locally

如果您不耐烦,请从 GitHub 获取代码并在本地集成