Ответ 1
Я рекомендую добавить класс @Startup
@Singleton
, который устанавливает соединение JDBC с базой данных PostgreSQL и использует LISTEN
и NOTIFY
для обработки недействительности кэша.
Обновить: Вот еще один интересный подход, использующий pgq и коллекцию работников для недействительности.
Сигнал о недействительности
Добавить триггер в обновляемой таблице, который отправляет NOTIFY
всякий раз, когда объект обновляется. В PostgreSQL 9.0 и выше этот NOTIFY
может содержать полезную нагрузку, обычно идентификатор строки, поэтому вам не нужно делать недействительным весь ваш кеш, а только сущность, которая изменилась. В более старых версиях, где полезная нагрузка не поддерживается, вы можете либо добавить недействительные записи в таблицу timestamped журнала, которая запрашивает ваш вспомогательный класс, когда он получает NOTIFY
, либо просто делает недействительным весь кеш.
Теперь ваш вспомогательный класс LISTEN
в событиях NOTIFY
, которые отправляет триггер. Когда он получает событие NOTIFY
, он может аннулировать отдельные записи кэша (см. Ниже) или очищать весь кеш. Вы можете слушать уведомления из базы данных PgJDBC слушать/уведомлять поддержку. Вам нужно будет развернуть управляемый пул соединений java.sql.Connection
, чтобы перейти к базовой реализации PostgreSQL, чтобы вы могли передать его на org.postgresql.PGConnection
и называть getNotifications()
на нем.
Альтернативой LISTEN
и NOTIFY
, вы можете опросить таблицу журналов изменений по таймеру и включить триггер в таблице проблем, добавить измененные идентификаторы строк и изменить временные метки в таблицу журнала изменений. Этот подход будет переносимым, за исключением необходимости использования другого триггера для каждого типа БД, но он неэффективен и менее своевременен. Это потребует частых неэффективных опросов и все еще имеет временную задержку, которую не поддерживает метод listen/notify. В PostgreSQL вы можете использовать таблицу UNLOGGED
, чтобы немного снизить затраты на этот подход.
Уровни кеша
EclipseLink/JPA имеет несколько уровней кэширования.
Кэш 1-го уровня находится на уровне EntityManager
. Если объект привязан к EntityManager
от persist(...)
, merge(...)
, find(...)
и т.д., Тогда EntityManager
требуется вернуть тот же экземпляр этого объекта, когда к нему снова обращаются в тот же сеанс, имеет ли ваше приложение все еще ссылки на него. Этот прикрепленный экземпляр не будет обновлен, если ваше содержимое базы данных с тех пор изменилось.
Кэш второго уровня, который является необязательным, находится на уровне EntityManagerFactory
и является более традиционным кешем. Неясно, включен ли кеш второго уровня. Проверьте журналы EclipseLink и persistence.xml
. Вы можете получить доступ к кешу 2-го уровня с помощью EntityManagerFactory.getCache()
; см. Cache
.
@thedayofcondor показал, как очистить кеш второго уровня:
em.getEntityManagerFactory().getCache().evictAll();
но вы также можете выселить отдельные объекты с помощью evict(java.lang.Class cls, java.lang.Object primaryKey)
:
em.getEntityManagerFactory().getCache().evict(theClass, thePrimaryKey);
который вы можете использовать из вашего прослушивателя @Startup
@Singleton
NOTIFY
, чтобы аннулировать только те записи, которые были изменены.
Кэш 1-го уровня не так просто, потому что он является частью вашей логики приложения. Вы захотите узнать, как работают EntityManager
, прикрепленные и отсоединенные объекты и т.д. Один из вариантов - всегда использовать отдельные элементы для рассматриваемой таблицы, где вы используете новый EntityManager
всякий раз, когда вы извлекаете объект. Этот вопрос:
Недействительный сеанс JPY EntityManager
имеет полезное обсуждение обработки недействительности кэша менеджера объектов. Однако маловероятно, что кеш EntityManager
является вашей проблемой, поскольку веб-служба RESTful обычно реализуется с использованием коротких сеансов EntityManager
. Вероятно, это может быть проблемой, если вы используете расширенные контексты персистентности, или если вы создаете и управляете своими собственными сеансами EntityManager
, а не используете постоянство, управляемое контейнером.