sql >> Base de Datos >  >> RDS >> PostgreSQL

¿Cómo actualizar las entidades JPA cuando la base de datos de back-end cambia de forma asíncrona?

Recomiendo agregar un @Startup @Singleton clase que establece una conexión JDBC a la base de datos PostgreSQL y usa LISTEN y NOTIFY para manejar la invalidación de caché.

Actualizar :Aquí hay otro enfoque interesante, usando pgq y una colección de trabajadores para la invalidación.

Señalización de invalidación

Agrega un disparador en la tabla que se está actualizando que envía un NOTIFY cada vez que se actualiza una entidad. En PostgreSQL 9.0 y superior este NOTIFY puede contener una carga útil, generalmente una ID de fila, por lo que no tiene que invalidar todo su caché, solo la entidad que ha cambiado. En versiones anteriores en las que no se admite una carga útil, puede agregar las entradas invalidadas a una tabla de registro con marca de tiempo que su clase auxiliar consulta cuando recibe un NOTIFY , o simplemente invalidar todo el caché.

Tu clase auxiliar ahora LISTEN s en el NOTIFY eventos que envía el activador. Cuando recibe un NOTIFY evento, puede invalidar entradas de caché individuales (ver a continuación) o vaciar todo el caché. Puede escuchar las notificaciones de la base de datos con el soporte de escucha/notificación de PgJDBC. Deberá desenvolver cualquier conexión java.sql.Connection administrada por el agrupador de conexiones para llegar a la implementación subyacente de PostgreSQL para que pueda enviarla a org.postgresql.PGConnection y llama a getNotifications() en él.

Una alternativa a LISTEN y NOTIFY , puede sondear una tabla de registro de cambios en un temporizador y hacer que un disparador en la tabla de problemas agregue los ID de fila cambiados y las marcas de tiempo de cambio a la tabla de registro de cambios. Este enfoque será portátil excepto por la necesidad de un activador diferente para cada tipo de base de datos, pero es ineficiente y menos oportuno. Requerirá un sondeo frecuente e ineficiente, y aún tendrá un retraso de tiempo que no tiene el enfoque de escucha/notificación. En PostgreSQL puede usar un UNLOGGED para reducir un poco los costos de este enfoque.

Niveles de caché

EclipseLink/JPA tiene un par de niveles de almacenamiento en caché.

El caché de primer nivel está en el EntityManager nivel. Si una entidad está adjunta a un EntityManager por persist(...) , merge(...) , find(...) , etc., entonces el EntityManager se requiere para devolver la misma instancia de esa entidad cuando se accede de nuevo dentro de la misma sesión, ya sea que su aplicación todavía tenga referencias a ella o no. Esta instancia adjunta no estará actualizada si el contenido de su base de datos ha cambiado desde entonces.

El caché de segundo nivel, que es opcional, está en EntityManagerFactory nivel y es un caché más tradicional. No está claro si tiene habilitado el caché de segundo nivel. Verifique sus registros de EclipseLink y su persistence.xml . Puede obtener acceso al caché de segundo nivel con EntityManagerFactory.getCache(); ver Cache .

@thedayofcondor mostró cómo vaciar el caché de segundo nivel con:

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

pero también puede desalojar objetos individuales con evict(java.lang.Class cls, java.lang.Object primaryKey) llamar:

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

que puedes usar desde tu @Startup @Singleton NOTIFY oyente para invalidar solo aquellas entradas que han cambiado.

El caché de primer nivel no es tan fácil, porque es parte de la lógica de su aplicación. Querrá saber cómo el EntityManager , entidades adscritas y separadas, etc. Una opción es usar siempre entidades separadas para la tabla en cuestión, donde usa un nuevo EntityManager cada vez que buscas la entidad. Esta pregunta:

Invalidando la sesión de JPA EntityManager

tiene una discusión útil sobre el manejo de la invalidación del caché del administrador de la entidad. Sin embargo, es poco probable que un EntityManager el caché es su problema, porque un servicio web RESTful generalmente se implementa usando EntityManager corto sesiones Es probable que esto solo sea un problema si está utilizando contextos de persistencia extendida, o si está creando y administrando su propio EntityManager sesiones en lugar de utilizar la persistencia administrada por contenedor.