How update/remove an item already cached within a collection of items

泄露秘密 提交于 2019-12-03 12:36:39

Caching the collection using the caching abstraction is a duplicate of what the underlying caching system is doing. And because this is a duplicate, it turns out that you have to resort to some kind of duplications in your own code in one way or the other (the duplicate key for the set is the obvious representation of that). And because there is duplication, you have to sync state somehow

If you really need to access to the whole set and individual elements, then you should probably use a shortcut for the easiest leg. First, you should make sure your cache contains all elements which is not something that is obvious. Far from it actually. Considering you have that:

//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 a call to values() may throw an exception. You may want to loop over the keys or something.

You have to remember that the caching abstraction eases the access to the underlying caching infrastructure and in no way it replaces it: if you had to use the API directly, this is probably what you would have to do in some sort.

Now, we can keep the conversion on SPR-12036 if you believe we can improve the caching abstraction in that area. Thanks!

I think something like this schould work... Actually it's only a variation if "Stéphane Nicoll" answer ofcourse, but it may be useful for someone. I write it right here and haven't check it in IDE, but something similar works in my Project.

  1. Override CacheResolver:

    @Cacheable(value="products", key="#root.target.PRODUCTS", cacheResolver = "customCacheResolver")
    
  2. Implement your own cache resolver, which search "inside" you cached items and do the work in 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's 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...
    }
    

Read more about CRUD of EhCache: EhCache code samples

Hope it helps. And sorry for my English:(

Though I don't see any easy way, but you can override Ehcache cache functionality by supplying cache decorator. Most probably you'd want to use EhcahceDecoratorAdapter, to enhance functions used by EhCacheCache put and evict methods.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!