2008-09-07 7 views
7

Nuestro diseño tiene un jvm que es un jboss/webapp (lectura/escritura) que se utiliza para mantener los datos a través de la hibernación (usando jpa) a la base de datos. El modelo tiene 10-15 clases persistentes con 3-5 niveles de profundidad en las relaciones.¿Cómo mantener la coherencia de la memoria caché de Hibernate con dos aplicaciones Java?

Tenemos entonces un jvm separado que es el servidor que utiliza esta información. Como está funcionando continuamente, solo tenemos una larga sesión de DB (solo lectura).

Actualmente no hay caché intra-jvm involucrado, por lo que manualmente señalamos un jvm desde el otro.

Ahora cuando la aplicación web cambia algunos datos, le indica al servidor que vuelva a cargar los datos modificados. Lo que hemos encontrado es que necesitamos decirle a hibernate que purgue los datos y luego los vuelva a cargar. Simplemente haciendo un fetch/merge con el DB no hace el trabajo, principalmente con respecto a los objetos de varias capas en la jerarquía.

Cualquier idea sobre si hay algo fundamentalmente malo en este diseño o si alguien está haciendo esto y ha tenido más suerte trabajando con hibernate en las recargas.

Gracias, Chris

Respuesta

10

Una sesión de Hibernate carga todos los datos que lee de la base de datos en lo que llaman la memoria caché de primer nivel . Una vez que se carga una fila desde el DB, cualquier recuperación posterior para una fila con el mismo PK devolverá los datos de este caché. Además, los gaurentees de Hibernate hacen referencia a la igualdad para los objetos con el mismo PK en una sola sesión.

Por lo que entiendo, su aplicación de servidor de solo lectura nunca cierra su sesión de Hibernate. Por lo tanto, cuando la base de datos se actualiza mediante la aplicación de lectura y escritura, la sesión en el servidor de solo lectura no tiene conocimiento del cambio. De hecho, su aplicación de solo lectura está cargando una copia en la memoria de la base de datos y utilizando esa copia, que se vuelve obsoleta a su debido tiempo.

El mejor y más simple curso de acción que puedo sugerir es cerrar y abrir sesiones según sea necesario. Esto elude todo el problema. Las sesiones de Hibernate están destinadas a ser una ventana para una interacción efímera con el DB. Estoy de acuerdo en que hay una ganancia de rendimiento al no volver a cargar el objeto-gráfico una y otra vez; pero debes medirlo y convencerte de que vale la pena.

Otra opción es cerrar y volver a abrir la sesión periódicamente. Esto asegura que la aplicación de solo lectura funciona con datos no anteriores a un intervalo de tiempo determinado. Pero definitivamente hay una ventana donde la aplicación de solo lectura funciona con datos obsoletos (aunque el diseño garantiza que obtenga los datos actualizados con el tiempo). Esto podría ser permisible en muchas aplicaciones; necesita evaluar su situación.

La tercera opción es utilizar un segundo nivel de aplicación caché, y el uso de Sesiones de corta duración. Hay varios paquetes de almacenamiento en caché que funcionan con Hibernate con méritos y deméritos relativos.

+0

El uso de la APP, y @PersistenceContext para obtener el EntityManager - pero parece que necesitamos para una @PersistenceUnit EntityManagerFactory y para actualizar los datos, obtenemos un nuevo EntityManager. Suena bien, pero es una forma pesada de actualizar las cosas, pero si eso es lo que hace la gente ... –

3

Chris, estoy un poco confundido acerca de sus circunstancias. Si entiendo correctamente, tiene una aplicación web (de lectura/escritura) independiente (solo lectura) que utiliza Hibernate para acceder a una base de datos compartida. Los cambios que realice con la aplicación web no son visibles para la aplicación independiente. ¿Está bien?

Si es así, ¿ha considerado utilizar una implementación de caché de segundo nivel diferente? Me pregunto si es posible que pueda usar un caché en clúster que sea compartido tanto por la aplicación web como por la aplicación independiente. Creo que SwarmCache, que está integrado con Hibernate, lo permitirá, pero yo no lo he probado.

En general, sin embargo, debe saber que el contenido de un caché determinado nunca será consciente de la actividad de otra aplicación (es por eso que sugiero que ambas aplicaciones compartan un caché). ¡Buena suerte!

2

Desde mi punto de vista, debe cambiar su subrayado Hibernate caché a aquel, que admite el modo agrupado. Podría ser JBoss Cache o Swarm Cache. El primero tiene una mejor compatibilidad con la sincronización de datos (replicación e invalidación) y también es compatible con JTA.

A continuación, podrá configurar la sincronización de caché entre la aplicación web y el servidor. También mire el nivel de aislamiento si usará JBoss Cache. Creo que debe utilizar el modo READ_COMMITTED si desea obtener datos nuevos en un servidor de la misma sesión.

1

La práctica más utilizada es tener un Container-Managed Entity Manager para que dos o más aplicaciones en el mismo contenedor (es decir, Glassfish, Tomcat, Websphere) puedan compartir los mismos cachés. ¡Pero si no usa un contenedor de aplicaciones, porque usa Play! por ejemplo, entonces construiría algunos servicios web en la aplicación principal para leer/escribir de forma coherente en la memoria caché.

Creo que usar datos obsoletos es una puerta abierta para el desastre. Al igual que los Singletons se convierten en Multitones, las aplicaciones de solo lectura a menudo son , escriben a veces.

cinturón y tirantes :)

Cuestiones relacionadas