#java #spring #caching #gemfire #spring-data-gemfire
#java #весна #кэширование #gemfire #весна-данные-gemfire
Вопрос:
Короче говоря, когда @CacheEvict вызывается в методе и если ключ для записи не найден, Gemfire выдает исключение EntryNotFoundException .
Теперь подробнее,
У меня есть класс
class Person {
String mobile;
int dept;
String name;
}
У меня есть две области кэша, определенные как personRegion и personByDeptRegion, и служба выглядит следующим образом
@Service
class PersonServiceImpl {
@Cacheable(value = "personRegion")
public Person findByMobile(String mobile) {
return personRepository.findByMobile(mobile);
}
@Cacheable(value = "personByDeptRegion")
public List<Person> findByDept(int deptCode) {
return personRepository.findByDept(deptCode);
}
@Caching(
evict = { @CacheEvict(value = "personByDeptRegion", key="#p0.dept"},
put = { @CachePut(value = "personRegion",key = "#p0.mobile")}
)
public Person updatePerson(Person p1) {
return personRepository.save(p1);
}
}
При вызове updatePerson и если в personByDeptRegion нет записей, это вызовет исключение, которое EntryNotFoundException для ключа 1 (или любого другого кода отдела). Существует очень большая вероятность того, что этот метод будет вызван до вызова методов @Cacheable, и вы хотите избежать этого исключения.
Есть ли какой-либо способ, которым мы могли бы настроить поведение Gemfire, чтобы корректно возвращать, когда ключ не существует для данного региона?.
В качестве альтернативы, я также хотел бы узнать, существует ли лучшая реализация вышеупомянутого сценария с использованием Gemfire в качестве кэша.
Источник данных Gemfire: 1.7.4
Версия Gemfire: v8.2.1
Примечание: Приведенный выше код предназначен только для представления, и у меня есть несколько сервисов с одинаковой проблемой в реальном проекте.
Комментарии:
1. Вау! Вам следует подумать об обновлении вашей версии SDG! 1.3.5.ВЫПУСК? o.O, как вы понимаете
1.8.4.RELEASE
, является самой последней версией (на основе GF 8.2.0). 1.7.6.RELEASE — поддерживаемая в настоящее время версия обслуживания (на основе GF 8.1.0). И в настоящее время разрабатывается SDG 1.9, при этом 1.9 M1 уже доступен, а 1.9 GA запланирован на 12 декабря. Вы можете оставаться в курсе, просматривая страницу проекта ЦУР ( projects.spring.io/spring-data-gemfire ) …2. … а также взглянуть на вики-страницу матрицы совместимости проекта ( github.com/spring-projects/spring-data-gemfire/wiki /… ). Кроме того, вы можете просмотреть сведения о выпуске на странице SD Wiki ( github.com/spring-projects/spring-data-commons/wiki ); смотрите навигационную колонку справа. Текущими версиями являются Gosling (SDG 1.7.6.RELEASE) и Hopper (SDG 1.8.4.RELEASE). Ingalls ( github.com/spring-projects/spring-data-commons/wiki /… ) находится в стадии разработки.
3. Сказав это… Я немного дополню «ответ» на ваш вопрос.
4. Мне очень жаль, Джон, я поставил версию spring boot вместо SDG: (Версия SDG 1.7.4 также обновлена в вопросе. Мы скоро перейдем на spring boot 1.4.1, поэтому я считаю, что это приведет к достижению 1,8 ЦУР 🙂
Ответ №1:
Во-первых, я рекомендую вам использовать аннотации кеширования Spring @Service
для компонентов вашего приложения. Слишком часто разработчики включают кэширование в своих репозиториях, что, на мой взгляд, является дурным тоном, особенно если сложные бизнес-правила (или даже дополнительный ввод-вывод; например, вызов веб-службы из компонента service) задействованы до или после взаимодействия с репозиторием (ами), особенно в случаях, когда поведение кэширования не должно бытьзатронуто (или определено).
Я также думаю, что ваше кэширование UC (обновление одного кэша ( personRegion
) при одновременном аннулировании другого ( personByDeptRegion
) при обновлении хранилища данных), следуя a CachePut
с a CacheEvict
, кажется мне разумным. Тем не менее, я хотел бы отметить, что, по-видимому, предполагаемое использование @Caching
аннотации заключается в объединении нескольких аннотаций кэширования одного и того же типа (например, множественных @CacheEvict
или множественных @CachePut
), как описано в справочном руководстве core Spring Framework . Тем не менее, ничто не мешает вашему предполагаемому использованию.
Я создал аналогичный тестовый класс здесь, смоделированный по вашему примеру выше, чтобы проверить проблему. Действительно, тестовый пример jonDoeUpdateSuccessful завершается неудачно (с GemFire EntryNotFoundException
, показанным ниже), поскольку ни один человек из Department
«R amp; D» ранее не кэшировался в « DepartmentPeople
» области GemFire до обновления, в отличие от тестового примера janeDoeUpdateSuccessful, который приводит к заполнению кэша до обновления (даже если запись не содержитзначения, что не имеет значения).
com.gemstone.gemfire.cache.EntryNotFoundException: RESEARCH_DEVELOPMENT
at com.gemstone.gemfire.internal.cache.AbstractRegionMap.destroy(AbstractRegionMap.java:1435)
ПРИМЕЧАНИЕ: в моем тесте GemFire используется как «поставщик кэша», так и система записей (SOR).
Проблема действительно заключается в использовании ЦУР Region.destroy(ключ) в реализации GemfireCache.evict(ключ), а не, и, возможно, более подходящего Region.remove(ключ).
GemfireCache.evict(key)
было реализовано с Region.destroy(key)
момента создания. Однако Region.remove(key)
оно не было введено до версии GemFire версии 5.0. Тем не менее, я не вижу заметной разницы между Region.destroy(key)
и Region.remove(key)
, кроме EntryNotFoundException
брошенного by Region.destroy(key)
. По сути, они оба уничтожают локальную запись (как ключ, так и значение), а также распространяют операцию на другие кэши в кластере (при условии, что используется не- LOCAL
область видимости).
Итак, я подал SGF-539, чтобы изменить SDG на вызов Region.remove(key)
, GemfireCache.evict(key)
а не Region.destroy(key)
.
Что касается обходного пути, ну, в принципе, вы можете сделать только 2 вещи:
- Реструктурируйте свой код и использование
@CacheEvict
аннотации и / или… - Используйте
condition
on@CacheEvict
.
К сожалению, a condition
нельзя указать с использованием типа класса, что-то похожее на условие Spring (в дополнение к SpEL), но этот интерфейс предназначен для другой цели, и @CacheEvict
condition
атрибут , не принимает тип класса.
На данный момент у меня нет хорошего примера того, как это может работать, поэтому я продвигаюсь вперед по SGF-539.
Вы можете следить за этим тикетом для получения более подробной информации и прогресса.
Извините за неудобства.
-Джон
Комментарии:
1. @Sandheep — У меня отличные новости… Я нашел обходной путь для вас, пока не разрешу SGF-539. Смотрите мой пример тестового класса обновления ( github.com/jxblum/spring-gemfire-tests/blob/master/src/test /… ) для получения более подробной информации.
2. Обратите внимание, ключ к «обходному пути» заключается в следующем … github.com/jxblum/spring-gemfire-tests/blob/master/src/test/… (именно то изменение в ЦУР, которое необходимо внести) … 😉
3. Отличный Джон :). Большое вам спасибо за создание заявки и особенно за немедленное решение проблемы. Я как бы застрял с этим. Протестирует обходной путь и сообщит вам.
4. Привет, Сандхип- 1 последнее обновление. Я разрешил / исправил SGF-539. Он был зафиксирован
1.7.x
(для Gosling 1.7.7.RELEASE),1.8.x
(для Хоппера 1.8.5.RELEASE)apache-geode
иmaster
(для Ingalls 1.9 RC1). К сожалению, только что вышли версии обслуживания SDG 1.7.6 и 1.8.4, а 1.7.7 / 1.8.5 не запланированы на некоторое время. 1.9 RC1 запланирован на конец ноября с окончательным 1.9 GA 12/12. Обходной путь работал безупречно в моем примере тестового класса. Если у вас возникнут проблемы, дайте мне знать. Приветствия!5. На месте 🙂 Я попробовал обходной путь, и он работает нормально. Однако у меня есть класс GemfireConfig, аннотированный с помощью @Configuration . Когда я добавил CacheManager в качестве компонента в этот класс, первый раз после запуска приложения выдал ту же ошибку, и последующие вызовы работали (подтверждено, что в обоих случаях кэш списка был пуст). Затем я переместил определение компонента в выделенный класс, а GemfireConfig имеет другие определения региона. Похоже, это устраняет проблему с первым запуском. Я не совсем уверен в причине. Но, похоже, это как-то связано с порядком создания компонента.