Препоръчвам да добавите @Startup
@Singleton
клас, който установява JDBC връзка към базата данни PostgreSQL и използва LISTEN
и NOTIFY
за обработка на невалидирането на кеша.
Актуализиране :Ето още един интересен подход, използващ pgq и колекция от работници за обезсилване.
Сигнализиране за невалидност
Добавете тригер към таблицата, която се актуализира, която изпраща NOTIFY
всеки път, когато даден обект се актуализира. На PostgreSQL 9.0 и по-нова версия това NOTIFY
може да съдържа полезен товар, обикновено идентификатор на ред, така че не е нужно да обезсилвате целия си кеш, а само обекта, който е променен. В по-стари версии, където полезен товар не се поддържа, можете или да добавите невалидните записи към таблица с времеви маркировки, която вашият помощен клас отправя към запитвания, когато получи NOTIFY
, или просто анулирайте целия кеш.
Вашият помощен клас сега LISTEN
s на NOTIFY
събития, които тригерът изпраща. Когато получи NOTIFY
събитие, може да анулира отделните записи в кеша (вижте по-долу) или да изчисти целия кеш. Можете да слушате за известия от базата данни с поддръжката за слушане/уведомяване на PgJDBC. Ще трябва да разгънете всеки пул за връзки, управляван java.sql.Connection
за да стигнете до основната реализация на PostgreSQL, за да можете да я прехвърлите към org.postgresql.PGConnection
и извикайте getNotifications()
върху него.
Алтернатива на LISTEN
и NOTIFY
, бихте могли да анкетирате таблица с регистрационни файлове за промени на таймер и да накарате тригер към таблицата с проблеми да добави променени идентификатори на редове и да промени времеви печати към таблицата на регистрационния файл на промените. Този подход ще бъде преносим, с изключение на необходимостта от различен тригер за всеки тип DB, но е неефективен и по-малко навременен. Това ще изисква често неефективно допитване и все пак ще има забавяне във времето, което подходът слушане/уведомяване няма. В PostgreSQL можете да използвате UNLOGGED
таблица, за да намалите малко разходите за този подход.
Нива на кеша
EclipseLink/JPA има няколко нива на кеширане.
Кешът от 1-во ниво е в EntityManager
ниво. Ако обект е прикачен към EntityManager
от persist(...)
, merge(...)
, find(...)
и т.н., след това EntityManager
се изисква да върне същия екземпляр на този обект когато бъде достъпен отново в рамките на същата сесия, независимо дали приложението ви все още има препратки към него. Този прикачен екземпляр няма да е актуален, ако съдържанието на базата ви оттогава се е променило.
Кешът от 2-ро ниво, който не е задължителен, е в EntityManagerFactory
ниво и е по-традиционен кеш. Не е ясно дали имате активиран кеш от 2-ро ниво. Проверете вашите регистрационни файлове на EclipseLink и вашия persistence.xml
. Можете да получите достъп до кеша от 2-ро ниво с EntityManagerFactory.getCache()
; вижте Cache
.
@thedayofcondor показа как да прочистите кеша от 2-ро ниво с:
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
всеки път, когато извлечете обекта. Този въпрос:
Невалидна сесия на JPA EntityManager
има полезна дискусия за обработка на невалидиране на кеша на мениджъра на обект. Малко вероятно е обаче EntityManager
кешът е вашият проблем, тъй като уеб услугата RESTful обикновено се реализира с помощта на кратък EntityManager
сесии. Това вероятно ще е проблем само ако използвате разширени контексти за постоянство или ако създавате и управлявате свой собствен EntityManager
сесии, вместо да се използва постоянство, управлявано от контейнер.