sql >> Database teknologi >  >> RDS >> PostgreSQL

Hvordan opdateres JPA-enheder, når backend-databasen ændres asynkront?

Jeg anbefaler at tilføje en @Startup @Singleton klasse, der etablerer en JDBC-forbindelse til PostgreSQL-databasen og bruger LISTEN og NOTIFY for at håndtere cache-invalidering.

Opdater :Her er en anden interessant tilgang, ved at bruge pgq og en samling arbejdere til ugyldiggørelse.

Ugyldighedssignalering

Tilføj en trigger på tabellen, der opdateres, og som sender en NOTIFY hver gang en enhed opdateres. På PostgreSQL 9.0 og over denne NOTIFY kan indeholde en nyttelast, normalt et række-id, så du ikke behøver at ugyldiggøre hele din cache, kun den enhed, der er ændret. På ældre versioner, hvor en nyttelast ikke understøttes, kan du enten tilføje de ugyldige poster til en tidsstemplet logtabel, som din hjælperklasse forespørger, når den får en NOTIFY , eller bare ugyldiggøre hele cachen.

Din hjælperklasse nu LISTEN s på NOTIFY hændelser, som triggeren sender. Når den får en NOTIFY hændelse, kan den ugyldiggøre individuelle cacheposter (se nedenfor) eller tømme hele cachen. Du kan lytte efter notifikationer fra databasen med PgJDBC's lytte/notify support. Du bliver nødt til at udpakke enhver forbindelsespooler-administreret java.sql.Connection for at komme til den underliggende PostgreSQL-implementering, så du kan caste den til org.postgresql.PGConnection og kald getNotifications() på den.

Et alternativ til LISTEN og NOTIFY , kan du polle en ændringslogtabel på en timer og få en trigger på problemtabellen til at tilføje ændrede række-id'er og ændre tidsstempler til ændringslogtabellen. Denne tilgang vil være bærbar, bortset fra behovet for en anden trigger for hver DB-type, men den er ineffektiv og mindre rettidig. Det vil kræve hyppige ineffektive afstemninger og stadig have en tidsforsinkelse, som lyt/besked-tilgangen ikke gør. I PostgreSQL kan du bruge en UNLOGGED tabel for at reducere omkostningerne ved denne fremgangsmåde en lille smule.

Cacheniveauer

EclipseLink/JPA har et par niveauer af caching.

Cachen på 1. niveau er i EntityManager niveau. Hvis en enhed er knyttet til en EntityManager af persist(...) , merge(...) , find(...) osv., derefter EntityManager er forpligtet til at returnere den samme forekomst af den pågældende enhed når den åbnes igen inden for samme session, uanset om din applikation stadig har referencer til den. Denne vedhæftede instans vil ikke være opdateret, hvis dit databaseindhold siden er ændret.

Cachen på 2. niveau, som er valgfri, er på EntityManagerFactory niveau og er en mere traditionel cache. Det er ikke klart, om du har 2. niveaus cache aktiveret. Tjek dine EclipseLink-logfiler og din persistence.xml . Du kan få adgang til cachen på 2. niveau med EntityManagerFactory.getCache(); se Cache .

@thedayofcondor viste, hvordan man skyller 2. niveaus cache med:

em.getEntityManagerFactory().getCache().evictAll();

men du kan også smide individuelle objekter ud med evict(java.lang.Class cls, java.lang.Object primaryKey) ring:

em.getEntityManagerFactory().getCache().evict(theClass, thePrimaryKey);

som du kan bruge fra din @Startup @Singleton NOTIFY lytteren for kun at ugyldiggøre de poster, der er ændret.

Cachen på 1. niveau er ikke så let, fordi den er en del af din applikationslogik. Du vil gerne lære om, hvordan EntityManager , tilknyttede og fritliggende enheder osv. arbejde. En mulighed er altid at bruge adskilte entiteter til den pågældende tabel, hvor du bruger en ny EntityManager hver gang du henter enheden. Dette spørgsmål:

Ugyldiggør JPA EntityManager-session

har en nyttig diskussion om håndtering af ugyldiggørelse af enhedsadministratorens cache. Det er dog usandsynligt, at en EntityManager cachen er dit problem, fordi en RESTful webservice normalt implementeres ved hjælp af kort EntityManager sessioner. Dette er sandsynligvis kun et problem, hvis du bruger udvidede persistenskontekster, eller hvis du opretter og administrerer din egen EntityManager sessioner i stedet for at bruge containerstyret persistens.



  1. Ændring af Django-udviklingsdatabase fra standard SQLite til PostgreSQL

  2. JSON_VALUE() Funktion i Oracle

  3. Sådan får du den aktuelle dato i MySQL

  4. LOAD DATA LOCAL INFILE giver fejlen Den brugte kommando er ikke tilladt med denne MySQL-version