3

我有一个服务,它调用外部系统通过它们的外部 id 检索某种对象,并将它们提交回更新。与其逐个检索对象,不如使用更通用的方法:

public interface ExternalSystem {
    List<ExternalDTO> getObjects(List<String> externalIds);

    void updateObjects(List<ExternalDTO> updates);
}

我想在 ExternalSystem 调用之上放置一个缓存,因为它们非常昂贵。

在服务的实现中,我可以简单地放置 spring 注释:

@Cacheable("cache-external")
List<ExternalDTO> getObjects(List<String> externalIds) {} 

@CacheEvict(cacheNames="cache-external", allEntries=true)
void updateObjects(List<ExternalDTO> updates);

但是,如果我在 externalIds 之间有很多交集,那么这样的缓存会表现得很糟糕,即

  1. 调用#1 getObjects([1,2,3,4]) -> 缓存由 [1,2,3,4] 键放置
  2. 调用#2 getObjects([1,2,3,4,5]) -> 缓存按 [1,2,3,4,5] 键放置
  3. 调用#3 getObjects([6,7,8,9]) -> 缓存按 [6,7,8,9] 键放置
  4. 调用#4 updateObjects( 1 ) -> 驱逐所有缓存,但第三个缓存不包含 3

所以,问题是如何实现自定义策略(我认为它不是开箱即用的),它将只驱逐那些真正应该被驱逐的条目,并使键以这样的方式从缓存中检索相交对象?

更新。我发现了两个类似的问题:

  1. spring-cache-abstraction-with-multi-value-queries
  2. using-spring-cache-on-methods-that-take-an-array-or-collection
  3. spring-cacheable-methods-with-lists

更新2。 这是与我想要的类似的东西,除了我将为集合中的每个项目放入 String 和 ExternalDTO 的缓存对。 列表到列表的元素级缓存

4

2 回答 2

0

AFAIK 这对于注释是不可能的。Cache.getAll(keySet)您可以使用命令式 API,其中包含您需要的批量操作,例如Cache.removeAll(keySet)

于 2016-05-20T09:27:01.217 回答
-1

对我来说,这个配置很好用。这是我的代码的混淆版本。

@Cacheable(cacheNames = "test", key = "#p0")
public List<String> getTestFunction(List<String> someIds) {
getTestFunction(Arrays.asList("A","B","C"));
2020-04-02 15:12:35.492 TRACE 18040 --- [Test worker] o.s.cache.interceptor.CacheInterceptor   : Computed cache key '[A, B, C]' for operation Builder[public java.util.List org.Main.getTestFunction(java.util.List)] caches=[test] | key='#p0' | keyGenerator='' | cacheManager='' | cacheResolver='' | condition='' | unless='' | sync='false'

你看到它连接了字符串

... Computed cache key '[A, B, C]' ...

我的设置:/resources/ehcache.xml

<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
    <cache name="test"
           maxBytesLocalHeap="1M"
           timeToLiveSeconds="300"/>
</ehcache>

gradle.build

plugins {
    id "org.springframework.boot" version "2.2.4.RELEASE"
    ....
}
dependencies {
    implementation "org.springframework.boot:spring-boot-starter-cache"
    implementation "org.ehcache:ehcache:3.8.1"
    ...
}

于 2020-04-02T13:19:13.580 回答