2009-10-01 16 views
8

Tengo una aplicación que utiliza JPA, Hibernate y ehcache, así como las transacciones declarativas de de Spring. La carga en DB es bastante alta, por lo que todo se almacena en caché para acelerar las cosas, incluidas las colecciones. Ahora no es un secreto que las colecciones se almacenan en caché por separado de las entidades que las poseen, así que si elimino una entidad que es un elemento de dicha colección en caché , persisto una entidad que debe ser un elemento de uno, o actualizo una entidad de modo que viaja de una colección a otra, debo realizar el desalojo a mano.Hibernate/Ehcache: colecciones de desalojo de la memoria caché de segundo nivel no sincronizadas con otras lecturas DB

lo que el uso de un detector de eventos de hibernación, que mantiene un registro de las entidades que se inserta, eliminados o actualizados y guarda esa información para una sincronización de operación registrada con el gestor de transacciones de primavera a actuar. La sincronización realiza el desalojo una vez que se ha confirmado la transacción .

Ahora el problema es que muy a menudo, alguna otra transacción simultánea logra encontrar una colección en la memoria caché que acaba de ser desalojado (estos eventos son por lo general décimas de segundo separados de acuerdo con log) y, naturalmente, , hace que ocurra una EntityNotFoundException.

¿Cómo sincronizo esto correctamente?

He intentado hacer el desalojo en cada uno de los 4 métodos de TransactionSynchronization (que se invocan en diferentes puntos en el tiempo en relación con la finalización de la transacción), no ayudó.

Respuesta

3

Esencialmente lo que debe hacer es forzar una lectura de la base de datos en el caso de que una colección esté en proceso o haya sido desalojada. Una forma de hacerlo sería marcar la colección como sucia tan pronto como se haya recibido una solicitud para desalojarla, pero antes de ingresar a la transacción para cambiarla. Cualquier transacción concurrente que se presente comprobará la bandera sucia y si está configurada como verdadera, debería obtener los datos de la base de datos, de lo contrario, puede leerlos desde la memoria caché. Es posible que deba cambiar la configuración de la transacción de su base de datos para que las transacciones simultáneas se bloqueen hasta que termine la actualización de los datos para que se lean los datos correctos de la base de datos. Una vez que finaliza la transacción, puede restablecer la bandera sucia a falso.

También puede crear un bloqueo en la colección en caché cuando una actualización, inserción o eliminación se vence mientras dure el desalojo. Esto asegurará que ninguna otra transacción pueda leer/cambiar la colección en caché hasta que finalice el proceso de desalojo.

+0

Se desalojó fuera de una transacción, por cierto. Y tengo que buscar la API para marcarlos sucios, gracias.Además, ¿cómo puedo sincronizar Hibernate en ese bloqueo que sugirió agregar? –

+1

Aparentemente, el indicador sucio de PersistentCollection no funcionará, porque transacciones diferentes obtienen instancias diferentes de la misma colección . En cuanto a las cerraduras, voy a analizar eso a continuación, y realmente agradecería que alguien me indicara cuál es la API correcta. EhCache no es compatible con el bloqueo por lo que sé, miró eso lo primero. –

0

¿Por qué no puede mantener las colecciones al día? es decir, cuando agrega un objeto, agregue el objeto a la colección a la que pertenece. Cuando elimina un objeto, elimínelo de la colección en la que se encuentra. Según mi experiencia al utilizar un caché con hibernación o jpa, el estado del objeto (no el estado de la base de datos) se almacena en caché, por lo que debe asegurarse de que su modelo de objetos en la memoria está sincronizado con el modelo de objetos en la base de datos.

¿O me está faltando algo? ¿Por qué no puedes simplemente mantener las colecciones al día?

+1

Es una aplicación de subprocesos múltiples, que pasa la misma instancia actualizada con una colección actualizada que parece bastante difícil, ya que hay todo tipo de operaciones simultáneas que tardan un tiempo diferente en completarse y tiendo a usar EntityManager. getById para obtener el último estado de una entidad. –

Cuestiones relacionadas