How to update / delete an item already cached in the item collection

I work with Spring and EhCache

I have the following method

@Override @Cacheable(value="products", key="#root.target.PRODUCTS") public Set<Product> findAll() { return new LinkedHashSet<>(this.productRepository.findAll()); } 

I have other methods for working with @Cacheable and @CachePut and @CacheEvict.

Now imagine that the database returns 100 products, and they are cached via key="#root.target.PRODUCTS" , then another method will insert - update - delete the item in the database. Therefore, products cached via key="#root.target.PRODUCTS" are no longer the same as the database.

I mean, check the following two two methods: they can update / delete the item and that the same item is cached in another key="#root.target.PRODUCTS"

 @Override @CachePut(value="products", key="#product.id") public Product update(Product product) { return this.productRepository.save(product); } @Override @CacheEvict(value="products", key="#id") public void delete(Integer id) { this.productRepository.delete(id); } 

I want to know if it is possible to update / delete an item in the cache via key="#root.target.PRODUCTS" , it will be 100 with the updated product or 499 if the Product was deleted.

My point is, I want to avoid the following:

 @Override @CachePut(value="products", key="#product.id") @CacheEvict(value="products", key="#root.target.PRODUCTS") public Product update(Product product) { return this.productRepository.save(product); } @Override @Caching(evict={ @CacheEvict(value="products", key="#id"), @CacheEvict(value="products", key="#root.target.PRODUCTS") }) public void delete(Integer id) { this.productRepository.delete(id); } 

I do not want to call again 500 or 499 products that will be cached in key="#root.target.PRODUCTS"

Is it possible? How?

Thanks in advance.

+8
source share
4 answers

Caching a collection using caching abstraction is a duplicate of what the underlying caching system does. And since this is a duplicate, it turns out that you need to resort to some kind of duplication in your own code, one way or another (a duplicate key for a set is an obvious representation of it). And since there is duplication, you need to somehow synchronize the state

If you really need access to the entire set and individual elements, then you should probably use a shortcut for the lightest leg. First, you need to make sure that your cache contains all elements that are not obvious. Far from him. Given that you have this:

 //EhCacheCache cache = (EhCacheCache) cacheManager.getCache("products"); @Override public Set<Product> findAll() { Ehcache nativeCache = cache.getNativeCache(); Map<Object, Element> elements = nativeCache.getAll(nativeCache.getKeys()); Set<Product> result = new HashSet<Product>(); for (Element element : elements.values()) { result.add((Product) element.getObjectValue()); } return Collections.unmodifiableSet(result); } 

The elements result is actually a lazy loaded map, so calling values() may throw an exception. You might want to flip keys or something like that.

You should remember that caching abstraction facilitates access to the underlying caching infrastructure and does not replace it in any way: if you needed to use the API directly, this is probably what you would need to do in some way.

Now we can save the transformation SPR-12036 , if you think that we can improve the caching of abstraction in this area. Thanks!

+5
source

I think something like this should work ... Actually this is only a variation if "Stéphane Nicoll" answers, of course, but it might be useful to someone. I am writing this right here and not testing it in the IDE, but something similar works in my project.

  • Override CacheResolver:

     @Cacheable(value="products", key="#root.target.PRODUCTS", cacheResolver = "customCacheResolver") 
  • Implement your own cache resolver that searches inside your cached items and does the work there

     public class CustomCacheResolver implements CacheResolver{ private static final String CACHE_NAME = "products"; @Autowired(required = true) private CacheManager cacheManager; @SuppressWarnings("unchecked") @Override public Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> cacheOperationInvocationContext) { // 1. Take key from query and create new simple key SimpleKey newKey; if (cacheOperationInvocationContext.getArgs().length != null) { //optional newKey = new SimpleKey(args); //It the key of cached object, which your "@Cachable" search for } else { //Schould never be... DEFAULT work with cache if something wrong with arguments return new ArrayList<>(Arrays.asList(cacheManager.getCache(CACHE_NAME))); } // 2. Take cache EhCacheCache ehCache = (EhCacheCache)cacheManager.getCache(CACHE_NAME); //this one we bringing back Ehcache cache = (Ehcache)ehCache.getNativeCache(); //and with this we working // 3. Modify existing Cache if we have it if (cache.getKeys().contains(newKey) && YouWantToModifyIt) { Element element = cache.get(key); if (element != null && !((List<Products>)element.getObjectValue()).isEmpty()) { List<Products> productsList = (List<Products>)element.getObjectValue(); // ---**--- Modify your "productsList" here as you want. You may now Change single element in this list. ehCache.put(key, anfragenList); //this method NOT adds cache, but OVERWRITE existing // 4. Maybe "Create" new cache with this key if we don't have it } else { ehCache.put(newKey, YOUR_ELEMENTS); } return new ArrayList<>(Arrays.asList(ehCache)); //Bring all back - our "new" or "modified" cache is in there now... } 

More on CRUD for EhCache: EhCache Code Examples

Hope this helps. And sorry for my english :(

+3
source

Although I don’t see any easy way, you can override the functionality of the Ehcache cache by providing a cache decorator . Most likely, you will want to use the EhcahceDecoratorAdapter to improve the functions used by EhCacheCache put and evict.

0
source

I need help, I use @Patch instead of @Put in springboot and only wanted to evict one record as soon as it was updated.

Can you help me

0
source

Source: https://habr.com/ru/post/972786/


All Articles