Как обновить / удалить элемент, уже кэшированный в коллекции элементов


Я работаю с Spring и EhCache

У меня есть следующий метод

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

У меня есть другие методы, работающие с @Cacheable и @CachePut и @CacheEvict.

Теперь представьте, что база данных возвращает 100 продуктов, и они кэшируются через key="#root.target.PRODUCTS", тогда другой метод вставит - обновит - удалит элемент в базу данных. Поэтому продукты, кэшируемые через key="#root.target.PRODUCTS", больше не являются такими же, как база данных.

Я имею в виду, проверьте два следующих два метода, они могут обновить / удалить элемент, и что тот же элемент кэшируется в другом 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);
}

Я хочу знать, возможно ли обновить / удалить элемент, расположенный в кэше через key="#root.target.PRODUCTS", это будет 100 с обновленным продуктом или 499, если продукт был удален.

Моя точка зрения заключается в том, что я хочу избежать следующего:

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

Я не хочу снова вызывать 500 или 499 продуктов, которые будут кэшироваться в key="#root.target.PRODUCTS"

Возможно ли это сделать? Но как?

Заранее благодарю.

3 7

3 ответа:

Кэширование коллекции с помощью абстракции кэширования является дубликатом того, что делает базовая система кэширования. И поскольку это дубликат, получается, что вы должны прибегнуть к некоторым дубликациям в своем собственном коде тем или иным способом (дубликат ключа для набора является очевидным представлением этого). И поскольку существует дублирование, вы должны каким-то образом синхронизировать состояние

Если вам действительно нужен доступ ко всему набору и отдельным элементам, то вы должны вероятно, используйте короткий путь для самой легкой ноги. Во-первых, вы должны убедиться, что ваш кэш содержит все элементы, которые не являются чем-то очевидным. На самом деле это далеко не так. Учитывая, что у вас есть это:

//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);
}

Результат elements на самом деле является ленивой загруженной картой, поэтому вызов values() может вызвать исключение. Возможно, вы захотите сделать петлю над ключами или что-то в этом роде.

Вы должны помнить, что абстракция кэширования облегчает доступ к базовой инфраструктуре кэширования и никоим образом не заменяет ее. it: если бы вам пришлось использовать API напрямую, это, вероятно, то, что вам пришлось бы сделать в некотором роде.

Теперь мы можем сохранить преобразование на SPR-12036 , Если вы считаете, что мы можем улучшить абстракцию кэширования в этой области. Спасибо!

Я думаю, что что-то вроде этого должно сработать... На самом деле это только вариант, если "Стефан Николл" ответ конечно, но это может быть полезно для кого-то. Я пишу его прямо здесь и не проверял его в IDE, но что-то подобное работает в моем проекте.

  1. Переопределить CacheResolver:

    @Cacheable(value="products", key="#root.target.PRODUCTS", cacheResolver = "customCacheResolver")
    
  2. Реализуйте свой собственный кэш-решатель, который ищет" внутри " ваших кэшированных элементов и выполняет работу там

    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...
    }
    

Подробнее о CRUD of EhCache: примеры кода EhCache

Надеюсь, это поможет. И извините за мой английский: (

Хотя я не вижу никакого простого способа, но вы можете переопределить функциональность кэша Ehcache, предоставивCache decorator . Скорее всего, вы захотите использовать EhcahceDecoratorAdapter, чтобы улучшить функции, используемые методами EhCacheCache put и exelt.