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:
@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
I'm not really sure what they mean by that, but I guess it has something to do with using regex in 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. 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?
Instead of using the annotations to find a key by a partial key, I've created a bean that manages the keys for me
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);
}
}
Instead of using multiple keys, concatenate the different keys into a single string
@Cacheable(cacheNames = "valueCodes", key = "#value.concat(#fieldId).concat(#projectId)")
Send the key to the service every time something is cached
cacheEvictionService.addKeyToList(StringUtils.join(value, fieldId, projectId));
Loop over every existing key that contains the project id (or any other key)
for (String cachedKey : cacheEvictionService.findKeyByPartialKey(projectId)) {
cacheEvictionService.evict(cachedKey);
}