Как обновить / удалить элемент, уже кэшированный в коллекции элементов
Я работаю с 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 ответа:
Кэширование коллекции с помощью абстракции кэширования является дубликатом того, что делает базовая система кэширования. И поскольку это дубликат, получается, что вы должны прибегнуть к некоторым дубликациям в своем собственном коде тем или иным способом (дубликат ключа для набора является очевидным представлением этого). И поскольку существует дублирование, вы должны каким-то образом синхронизировать состояние
Если вам действительно нужен доступ ко всему набору и отдельным элементам, то вы должны вероятно, используйте короткий путь для самой легкой ноги. Во-первых, вы должны убедиться, что ваш кэш содержит все элементы, которые не являются чем-то очевидным. На самом деле это далеко не так. Учитывая, что у вас есть это:
//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, но что-то подобное работает в моем проекте.
Переопределить CacheResolver:
@Cacheable(value="products", key="#root.target.PRODUCTS", cacheResolver = "customCacheResolver")
Реализуйте свой собственный кэш-решатель, который ищет" внутри " ваших кэшированных элементов и выполняет работу там
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.