Ik raad aan om een @Startup
. toe te voegen @Singleton
klasse die een JDBC-verbinding tot stand brengt met de PostgreSQL-database en gebruikmaakt van LISTEN
en NOTIFY
om cache-invalidatie af te handelen.
Bijwerken :Hier is nog een interessante benadering, met behulp van pgq en een verzameling werkers voor ongeldigverklaring.
Ongeldige signalering
Voeg een trigger toe aan de tabel die wordt bijgewerkt en die een NOTIFY
. verzendt telkens wanneer een entiteit wordt bijgewerkt. Op PostgreSQL 9.0 en hoger deze NOTIFY
kan een payload bevatten, meestal een rij-ID, dus u hoeft niet uw hele cache ongeldig te maken, alleen de entiteit die is gewijzigd. Op oudere versies waar een payload niet wordt ondersteund, kunt u de ongeldige vermeldingen toevoegen aan een logboektabel met tijdstempel die uw helperklasse opvraagt wanneer deze een NOTIFY
krijgt , of maak gewoon de hele cache ongeldig.
Je hulpklas nu LISTEN
s op de NOTIFY
gebeurtenissen die de trigger verzendt. Wanneer het een NOTIFY
. krijgt gebeurtenis, kan het individuele cache-items ongeldig maken (zie hieronder), of de hele cache leegmaken. U kunt luisteren naar meldingen uit de database met PgJDBC's luister-/meldingsondersteuning. U moet elke door verbindingspooler beheerde java.sql.Connection
. uitpakken om bij de onderliggende PostgreSQL-implementatie te komen, zodat u deze kunt casten naar org.postgresql.PGConnection
en bel getNotifications()
erop.
Een alternatief voor LISTEN
en NOTIFY
, u kunt een wijzigingslogboektabel op een timer pollen en een trigger op de probleemtabel laten wijzigen rij-ID's en tijdstempels wijzigen in de wijzigingslogboektabel. Deze aanpak is draagbaar, behalve dat er voor elk DB-type een andere trigger nodig is, maar is inefficiënt en minder actueel. Het vereist frequente inefficiënte polling en heeft nog steeds een vertraging die de luister-/meldingsbenadering niet heeft. In PostgreSQL kunt u een UNLOGGED
. gebruiken tabel om de kosten van deze aanpak een beetje te verlagen.
Cacheniveaus
EclipseLink/JPA heeft een aantal cachingniveaus.
De cache van het 1e niveau bevindt zich in de EntityManager
peil. Als een entiteit is gekoppeld aan een EntityManager
door persist(...)
, merge(...)
, find(...)
, etc, dan de EntityManager
is vereist om dezelfde instantie van die entiteit te retourneren wanneer het binnen dezelfde sessie opnieuw wordt geopend, ongeacht of uw toepassing er nog steeds naar verwijst. Dit bijgevoegde exemplaar is niet up-to-date als de inhoud van uw database sindsdien is gewijzigd.
De cache van het 2e niveau, die optioneel is, bevindt zich in de EntityManagerFactory
level en is een meer traditionele cache. Het is niet duidelijk of u de cache van het 2e niveau hebt ingeschakeld. Controleer uw EclipseLink-logboeken en uw persistence.xml
. U kunt toegang krijgen tot de cache van het 2e niveau met EntityManagerFactory.getCache()
; zie Cache
.
@thedayofcondor liet zien hoe je de cache van het 2e niveau leegmaakt met:
em.getEntityManagerFactory().getCache().evictAll();
maar u kunt ook individuele objecten verwijderen met de evict(java.lang.Class cls, java.lang.Object primaryKey)
bel:
em.getEntityManagerFactory().getCache().evict(theClass, thePrimaryKey);
die u kunt gebruiken vanaf uw @Startup
@Singleton
NOTIFY
luisteraar om alleen die vermeldingen ongeldig te maken die zijn gewijzigd.
De cache van het eerste niveau is niet zo eenvoudig, omdat het deel uitmaakt van uw toepassingslogica. U wilt weten hoe de EntityManager
, gekoppelde en vrijstaande entiteiten, enz. werken. Een optie is om voor de betreffende tabel altijd vrijstaande entiteiten te gebruiken, waarbij je een nieuwe EntityManager
gebruikt. telkens wanneer u de entiteit ophaalt. Deze vraag:
JPA EntityManager-sessie ongeldig maken
heeft een nuttige bespreking van het afhandelen van ongeldigverklaring van de cache van de entiteitsmanager. Het is echter onwaarschijnlijk dat een EntityManager
cache is jouw probleem, omdat een RESTful-webservice meestal wordt geïmplementeerd met behulp van de korte EntityManager
sessies. Dit is waarschijnlijk alleen een probleem als u uitgebreide persistentiecontexten gebruikt of als u uw eigen EntityManager
maakt en beheert. sessies in plaats van door containerbeheerde persistentie te gebruiken.