2016-12-06 3 views
3

Dans mon application, j'ai plusieurs méthodes cacheable avec plusieurs clés:evict Cache sur l'une des touches multiples

@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}") 

Maintenant, je veux une méthode cachevict qui cleares toutes les caches où ne la touche #projectId , qui est un UUID, correspond à:

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

J'ai lu dans this article que ce n'est pas possible et que

Seul le dans chacune des cacheNames d'annotation evict regex clé correspondant à plus d'un élément

Je ne suis pas vraiment sûr de ce qu'ils veulent dire par là, mais je suppose qu'il a quelque chose à voir avec l'aide regex dans SpEL.

Je commencé à penser à concatinating mes clés dans une clé:

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

et en utilisant regex pour correspondre à toutes les touches avec le projectId suivi d'un caractère générique. Mais je ne pouvais pas vraiment trouver un moyen de le faire.

Est-ce que ce que j'essaie d'accomplir est possible? Si oui, comment je fais ça?

Répondre

0

Au lieu d'utiliser les annotations pour trouver une clé par une clé partielle, j'ai créé un haricot qui gère les clés pour moi

  1. j'ai enlevé toutes les annotations de @CacheEvict.
  2. A créé un nouveau service qui va gérer l'expulsion pour tous nos 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. Au lieu d'utiliser plusieurs touches, concaténer les différentes clés en une seule chaîne

    @Cacheable(cacheNames = "valueCodes", key = "#value.concat(#fieldId).concat(#projectId)") 
    
  4. Envoyer la clé du service chaque fois que quelque chose est mis en cache

    cacheEvictionService.addKeyToList(StringUtils.join(value, fieldId, projectId)); 
    
  5. boucle sur toutes les clés existantes qui contient l'identifiant du projet (ou toute autre touche)

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

Est-ce que ce que j'essaie d'accomplir est possible? Si oui, comment je fais ça?

Ce que vous aimez faire n'est pas possible.

En général, un cache agit comme une table de hachage, vous ne pouvez opérer que sur une clé unique. La sélection de tout ce qui appartient à un identifiant de projet nécessiterait un index et un mécanisme de requête dans le cache. Certains caches ont cela, mais pas tous, et il n'y a pas de norme commune pour ce faire. Vérifiez à nouveau s'il est vraiment judicieux de mettre en cache séparément tous les éléments qui appartiennent à un projet. Si tout doit être évincé ensemble, peut-être qu'il est utilisé ensemble tout le temps. Vous pouvez également, par exemple, conserver une valeur ConcurrentHashMap dans le cache qui contient les divers composants appartenant à un projet.

Plus sur ce sujet, voir la question suivante: What is the better option for a multi-level, in-process cache?

Probablement il est logique de déposer des annotations et utiliser un cache directement. Les options avec des annotations sont limitées.

+0

J'ai trouvé un moyen simple de faire cela, mais nécessite un peu plus de code sur ma fin. Dans le cas où vous êtes intéressé par la solution, jetez un oeil à mes solutions. –