Кеш выталкивает на один из нескольких ключей
В моем приложении у меня есть несколько кэшируемых методов с несколькими ключами:
@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}")
Теперь я хочу метод cachevict, который очищает все кеши, где совпадает только ключ #projectId, который является UUID:
@CacheEvict(value = {"valueCodes", "fieldCodes", "qi"; "fieldCodes"}, key = "#projectId")
Я читал в этой статье, что это невозможно и что
Только регулярное выражение ключа аннотации выселения, совпадающее с более чем одним элементом в каждом из имен cacheNames
Я не совсем уверен, что они подразумевают под этим, но я думаю, это как-то связано с использованием регулярных выражений в SpEL.
Поэтому я начал думать о соединении моих ключей в один ключ:
@Cacheable(cacheNames="cahceName", key="concat(#projectId).concat(#otherKey)")
и использование регулярного выражения для сопоставления всех ключей с идентификатором проекта, за которым следует подстановочный знак. Но я не мог найти способ сделать это.
Возможно ли то, что я пытаюсь достичь? Если да, то как мне это сделать?
2 ответа
Вместо того, чтобы использовать аннотации для поиска ключа по частичному ключу, я создал компонент, который управляет ключами для меня
- Я удалил все аннотации @CacheEvict.
Создан новый сервис, который будет управлять выселением для всех наших кешей
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); } }
Вместо использования нескольких ключей объедините различные ключи в одну строку
@Cacheable(cacheNames = "valueCodes", key = "#value.concat(#fieldId).concat(#projectId)")
Отправляйте ключ в сервис каждый раз, когда что-то кешируется
cacheEvictionService.addKeyToList(StringUtils.join(value, fieldId, projectId));
Цикл по каждому существующему ключу, который содержит идентификатор проекта (или любой другой ключ)
for (String cachedKey : cacheEvictionService.findKeyByPartialKey(projectId)) { cacheEvictionService.evict(cachedKey); }
Возможно ли то, что я пытаюсь достичь? Если да, то как мне это сделать?
То, что вы любите делать, невозможно.
В общем случае кеш работает как хеш-таблица, вы можете работать только с уникальным ключом. Выбор всего, что принадлежит идентификатору проекта, потребует индекса и механизма запросов в кеше. Это есть у некоторых кешей, но не у всех, и нет единого стандарта, как это делается.
Дважды проверьте, имеет ли смысл кэшировать все фрагменты, которые принадлежат проекту, отдельно. Если все должно быть выселено вместе, возможно, оно используется вместе все время. В качестве альтернативы, например, сохранить ConcurrentHashMap
в качестве значения в кеше, который содержит различные компоненты, принадлежащие проекту.
Подробнее об этом см. Вопрос: что является лучшим вариантом для многоуровневого внутрипроцессного кэша?
Вероятно, имеет смысл отбросить аннотации и использовать кеш напрямую. Варианты с аннотациями ограничены.