简体   繁体   English

缓存在多个密钥之一上逐出

[英]Cache evict on one of multiple keys

In my application I have multiple cacheable methods with multiple keys: 在我的应用程序中,我有多个具有多个键的可缓存方法:

@Cacheable(cacheNames = "valueCodes", key = "{#value, #fieldId, #projectId}")
@Cacheable(cacheNames = "fieldNames", key = "{#field, #value, #projectId}")
@Cacheable(cacheNames = "qi", key = "{#langCode, #question, #projectId}")
@Cacheable(cacheNames = "fieldCodes", key = "{#name, #projectId}")

Now I want a cachevict method which cleares all the caches where only the #projectId key, which is a UUID, matches: 现在我想要一个cachevict方法,它清除所有只有 #projectId键(UUID)匹配的缓存:

@CacheEvict(value = {"valueCodes", "fieldCodes", "qi"; "fieldCodes"}, key = "#projectId")

I've read in this article that this is not possible and that 我在这篇文章中读到这是不可能的

Only the evict annotation's key regex matching more than one element in each of the cacheNames 只有evict注释的关键正则表达式匹配每个cacheNames中的多个元素

I'm not really sure what they mean by that, but I guess it has something to do with using regex in SpEL . 我不太确定它们的意思,但我想这与在SpEL中使用正则表达式有关

So I started thinking about concatinating my keys into one key: 所以我开始考虑将我的密钥合并为一个密钥:

@Cacheable(cacheNames="cahceName", key="concat(#projectId).concat(#otherKey)")

and using regex to match all keys with the projectId followed by a wildcard. 并使用正则表达式将所有键与projectId匹配,后跟通配符。 But I couldn't really find a way to do this. 但我真的找不到办法做到这一点。

Is what I'm trying to accomplish possible? 我正在努力实现的目标是什么? If so, how do I do this? 如果是这样,我该怎么做?

Is what I'm trying to accomplish possible? 我正在努力实现的目标是什么? If so, how do I do this? 如果是这样,我该怎么做?

What you like to do is not possible. 你不想做什么。

In general a cache acts like a hash table, you can only operate on a unique key. 通常,缓存的行为类似于哈希表,您只能对唯一键进行操作。 Selecting everything which belongs to a project id would require an index and a query mechanism in the cache. 选择属于项目id的所有内容将需要缓存中的索引和查询机制。 Some caches have that, but not all, and there is no common standard how this is done. 有些缓存有,但不是全部,并且没有共同的标准如何完成。

Double check whether it really makes sense to cache all the bits and pieces that belong to a project separately. 仔细检查是否真的有意义地分别缓存属于项目的所有零碎。 If everything needs to be evicted together, maybe it is used together all the time. 如果一切都需要一起驱逐,也许它一直在一起使用。 Alternatively, for example, keep a ConcurrentHashMap as value in the cache which holds the various components belonging to a project. 或者,例如,将ConcurrentHashMap保留为缓存中的值,该缓存中包含属于项目的各种组件。

More on this, see the question: What is the better option for a multi-level, in-process cache? 更多相关信息,请参阅以下问题: 对于多级进程内缓存,更好的选择是什么?

Probably it makes sense to drop annotations and use a cache directly. 删除注释并直接使用缓存可能是有意义的。 The options with annotations are limited. 带注释的选项有限。

Instead of using the annotations to find a key by a partial key, I've created a bean that manages the keys for me 我没有使用注释来通过部分键找到键,而是创建了一个为我管理键的bean

  1. I removed all the @CacheEvict annotations. 我删除了所有的@CacheEvict注释。
  2. Created a new service that'll manage the eviction for all of our caches 创建了一项新服务,可以管理所有缓存的驱逐

     public interface CacheEvictionService { /** * Adds the provided key to a global list of keys that we'll need later for eviction * * @param key the cached key for any entry */ void addKeyToList(String key); /** * Find keys that contain the partial key * * @param partialKey the cached partial key for an entry * @return List of matching keys */ List<String> findKeyByPartialKey(String partialKey); /** * Evicts the cache and key for an entry matching the provided key * * @param key the key of the entry you want to evict */ void evict(String key); } @Service public class CacheEvictionServiceImpl implements CacheEvictionService { LinkedHashSet<String> cachedKeys = new LinkedHashSet<>(); @Override public void addKeyToList(String key) { this.cachedKeys.add(key); } @Override public List<String> findKeyByPartialKey(String partialKey) { List<String> foundKeys = new ArrayList<>(); for (String cachedKey : this.cachedKeys) { if (cachedKey.contains(partialKey)) { foundKeys.add(cachedKey); } } return foundKeys; } @Override @CacheEvict(value = {"valueCodes", "fieldCodes", "qi", "fieldNames", "fieldsByType"}, key = "#key") public void evict(String key) { this.cachedKeys.remove(key); } } 
  3. Instead of using multiple keys, concatenate the different keys into a single string 不使用多个键,而是将不同的键连接成一个字符串

     @Cacheable(cacheNames = "valueCodes", key = "#value.concat(#fieldId).concat(#projectId)") 
  4. Send the key to the service every time something is cached 每次缓存某些内容时都会将密钥发送给服务

     cacheEvictionService.addKeyToList(StringUtils.join(value, fieldId, projectId)); 
  5. Loop over every existing key that contains the project id (or any other key) 遍历包含项目ID(或任何其他键)的每个现有密钥

     for (String cachedKey : cacheEvictionService.findKeyByPartialKey(projectId)) { cacheEvictionService.evict(cachedKey); } 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM