PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Wie werden JPA-Entitäten aktualisiert, wenn sich die Back-End-Datenbank asynchron ändert?

Ich empfehle das Hinzufügen eines @Startup @Singleton Klasse, die eine JDBC-Verbindung zur PostgreSQL-Datenbank herstellt und LISTEN verwendet und NOTIFY um die Cache-Invalidierung zu handhaben.

Aktualisieren :Hier ist ein weiterer interessanter Ansatz, der pgq und eine Sammlung von Arbeitern für die Invalidierung verwendet.

Invalidierungssignalisierung

Fügen Sie der zu aktualisierenden Tabelle einen Trigger hinzu, der ein NOTIFY sendet immer wenn eine Entität aktualisiert wird. Auf PostgreSQL 9.0 und höher dieses NOTIFY kann eine Nutzlast enthalten, normalerweise eine Zeilen-ID, sodass Sie nicht Ihren gesamten Cache ungültig machen müssen, sondern nur die Entität, die sich geändert hat. In älteren Versionen, in denen eine Payload nicht unterstützt wird, können Sie entweder die ungültigen Einträge zu einer mit Zeitstempel versehenen Protokolltabelle hinzufügen, die Ihre Hilfsklasse abfragt, wenn sie ein NOTIFY erhält , oder einfach den gesamten Cache ungültig machen.

Ihre Hilfsklasse ist jetzt LISTEN s auf NOTIFY Ereignisse, die der Trigger sendet. Wenn es ein NOTIFY erhält Event kann es einzelne Cache-Einträge ungültig machen (siehe unten) oder den gesamten Cache leeren. Mit der Listen/Notify-Unterstützung von PgJDBC können Sie auf Benachrichtigungen aus der Datenbank warten. Sie müssen alle vom Verbindungspooler verwalteten java.sql.Connection entpacken um zur zugrunde liegenden PostgreSQL-Implementierung zu gelangen, damit Sie sie in org.postgresql.PGConnection umwandeln können und rufen Sie getNotifications() auf drauf.

Eine Alternative zu LISTEN und NOTIFY , könnten Sie eine Änderungsprotokolltabelle mit einem Timer abfragen und einen Trigger für die Problemtabelle haben, der geänderte Zeilen-IDs anhängt und Zeitstempel an die Änderungsprotokolltabelle ändert. Dieser Ansatz ist übertragbar, abgesehen von der Notwendigkeit eines anderen Triggers für jeden DB-Typ, aber er ist ineffizient und weniger zeitgemäß. Es erfordert ein häufiges ineffizientes Abfragen und hat dennoch eine Zeitverzögerung, die der Listen/Notify-Ansatz nicht hat. In PostgreSQL können Sie einen UNLOGGED verwenden um die Kosten dieses Ansatzes etwas zu reduzieren.

Cache-Ebenen

EclipseLink/JPA hat mehrere Caching-Ebenen.

Der Cache der 1. Ebene befindet sich im EntityManager Stufe. Wenn eine Entität an einen EntityManager angehängt ist durch persist(...) , merge(...) , find(...) , etc, dann den EntityManager ist erforderlich, um dieselbe Instanz dieser Entität zurückzugeben bei einem erneuten Zugriff innerhalb derselben Sitzung, unabhängig davon, ob Ihre Anwendung noch darauf verweist. Diese angehängte Instanz ist nicht mehr aktuell, wenn sich Ihre Datenbankinhalte seitdem geändert haben.

Der 2nd-Level-Cache, der optional ist, befindet sich in der EntityManagerFactory Level und ist ein eher traditioneller Cache. Es ist nicht klar, ob Sie den 2nd-Level-Cache aktiviert haben. Überprüfen Sie Ihre EclipseLink-Protokolle und Ihre persistence.xml . Mit EntityManagerFactory.getCache() erhalten Sie Zugriff auf den 2nd-Level-Cache; siehe Cache .

@thedayofcondor zeigte, wie man den 2nd-Level-Cache leert mit:

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

Sie können aber auch einzelne Objekte mit evict(java.lang.Class cls, java.lang.Object primaryKey) entfernen Aufruf:

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

die Sie von Ihrem @Startup aus verwenden können @Singleton NOTIFY Listener, um nur die Einträge ungültig zu machen, die sich geändert haben.

Der 1st-Level-Cache ist nicht so einfach, da er Teil Ihrer Anwendungslogik ist. Sie sollten erfahren, wie der EntityManager , angeschlossene und freistehende Einheiten usw. arbeiten. Eine Möglichkeit besteht darin, immer getrennte Entitäten für die betreffende Tabelle zu verwenden, wobei Sie einen neuen EntityManager verwenden wann immer Sie die Entität abrufen. Diese Frage:

JPA EntityManager-Sitzung wird ungültig

hat eine nützliche Diskussion über den Umgang mit der Invalidierung des Caches des Entitätsmanagers. Es ist jedoch unwahrscheinlich, dass ein EntityManager Cache ist Ihr Problem, denn ein RESTful Webservice wird normalerweise mit dem kurzen EntityManager implementiert Sitzungen. Dies ist wahrscheinlich nur dann ein Problem, wenn Sie erweiterte Persistenzkontexte verwenden oder wenn Sie Ihren eigenen EntityManager erstellen und verwalten Sitzungen, anstatt Container-verwaltete Persistenz zu verwenden.