PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Comment actualiser les entités JPA lorsque la base de données principale change de manière asynchrone ?

Je recommande d'ajouter un @Startup @Singleton classe qui établit une connexion JDBC à la base de données PostgreSQL et utilise LISTEN et NOTIFY pour gérer l'invalidation du cache.

Mettre à jour :Voici une autre approche intéressante, utilisant pgq et une collection de travailleurs pour l'invalidation.

Signalisation d'invalidation

Ajoutez un déclencheur sur la table en cours de mise à jour qui envoie un NOTIFY chaque fois qu'une entité est mise à jour. Sur PostgreSQL 9.0 et supérieur, ce NOTIFY peut contenir une charge utile, généralement un ID de ligne, de sorte que vous n'avez pas à invalider l'intégralité de votre cache, uniquement l'entité qui a changé. Sur les anciennes versions où une charge utile n'est pas prise en charge, vous pouvez soit ajouter les entrées invalidées à une table de journal horodatée que votre classe d'assistance interroge lorsqu'elle reçoit un NOTIFY , ou simplement invalider tout le cache.

Votre classe d'assistance maintenant LISTEN s sur le NOTIFY événements que le déclencheur envoie. Quand il reçoit un NOTIFY événement, il peut invalider des entrées de cache individuelles (voir ci-dessous) ou vider tout le cache. Vous pouvez écouter les notifications de la base de données avec le support d'écoute/notification de PgJDBC. Vous devrez déballer toute connexion gérée par le pooler java.sql.Connection pour accéder à l'implémentation PostgreSQL sous-jacente afin de pouvoir la convertir en org.postgresql.PGConnection et appelez getNotifications() dessus.

Une alternative à LISTEN et NOTIFY , vous pouvez interroger une table du journal des modifications sur une minuterie et disposer d'un déclencheur sur la table des problèmes pour ajouter les ID de ligne modifiés et modifier les horodatages dans la table du journal des modifications. Cette approche sera portable à l'exception de la nécessité d'un déclencheur différent pour chaque type de base de données, mais elle est inefficace et moins rapide. Cela nécessitera des interrogations fréquentes et inefficaces, et aura toujours un délai que l'approche d'écoute/notification n'a pas. Dans PostgreSQL, vous pouvez utiliser un UNLOGGED tableau pour réduire un peu les coûts de cette approche.

Niveaux de cache

EclipseLink/JPA a plusieurs niveaux de mise en cache.

Le cache de 1er niveau est au EntityManager niveau. Si une entité est attachée à un EntityManager par persist(...) , merge(...) , find(...) , etc, puis le EntityManager est nécessaire pour renvoyer la même instance de cette entité lorsqu'on y accède à nouveau au cours de la même session, que votre application y fasse toujours référence ou non. Cette instance attachée ne sera pas à jour si le contenu de votre base de données a changé depuis.

Le cache de 2e niveau, qui est facultatif, se trouve dans EntityManagerFactory niveau et est un cache plus traditionnel. Il n'est pas clair si vous avez activé le cache de 2ème niveau. Vérifiez vos journaux EclipseLink et votre persistence.xml . Vous pouvez accéder au cache de 2ème niveau avec EntityManagerFactory.getCache(); voir Cache .

@thedayofcondor a montré comment vider le cache de 2ème niveau avec :

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

mais vous pouvez également expulser des objets individuels avec le evict(java.lang.Class cls, java.lang.Object primaryKey) appeler :

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

que vous pouvez utiliser depuis votre @Startup @Singleton NOTIFY écouteur pour invalider uniquement les entrées qui ont changé.

Le cache de 1er niveau n'est pas si facile, car il fait partie de la logique de votre application. Vous voudrez en savoir plus sur la façon dont le EntityManager , entités attachées et détachées, etc. fonctionnent. Une option consiste à toujours utiliser des entités détachées pour la table en question, où vous utilisez un nouveau EntityManager chaque fois que vous récupérez l'entité. Cette question :

Invalidation de la session JPA EntityManager

a une discussion utile sur la gestion de l'invalidation du cache du gestionnaire d'entités. Cependant, il est peu probable qu'un EntityManager cache est votre problème, car un service Web RESTful est généralement implémenté à l'aide d'un raccourci EntityManager séances. Cela ne risque de poser problème que si vous utilisez des contextes de persistance étendue ou si vous créez et gérez votre propre EntityManager sessions plutôt que d'utiliser la persistance gérée par le conteneur.