2012-09-27 19 views
26

Primero olvidemos Hibernate. Supongamos que tengo dos tablas, A & B. Dos transacciones están actualizando los mismos registros en estas dos tablas, pero txn 1 actualiza B y luego A, mientras que txn 2 actualiza A luego B. Este es un típico ejemplo de interbloqueo. La forma más común de evitar esto es predefinir el orden de adquisición de recursos. Por ejemplo, debemos actualizar la tabla A y luego B.Cómo está Hibernate decidiendo el orden de actualización/inserción/eliminación

Volver a Hibernate. Cuando estamos actualizando muchas entidades en una sesión, una vez que estoy descargando la sesión, los cambios de las diferentes entidades generarán las correspondientes instrucciones de inserción/actualización/eliminación en la base de datos. ¿Hibernate tiene algún algoritmo para decidir el orden de actualización entre las entidades? De lo contrario, ¿cuál es la forma en que Hibernate utilizó para prevenir la situación de estancamiento descrita en el 1er párrafo?

Si Hibernate mantiene el orden, ¿cómo puedo saber o controlar el pedido? No quiero que mi actualización explícita en conflictos de DB con Hibernate, y causar un punto muerto.

Respuesta

29

El problema que usted describe no es manejado por la base de datos, y según mi experiencia, Hibernate tampoco lo maneja del todo.

Debe tomar medidas explícitas para evitar que sea un problema.

Hibernate hace parte del trabajo por usted. Según la respuesta anterior, Hibernate garantiza que, dentro de una descarga aislada, las inserciones, eliminaciones y actualizaciones se ordenan de forma que garantice que se aplicarán en un orden alcanzable.Ver performExecutions(EventSource session) en la clase AbstractFlushingEventListener:

ejecutar todas SQL (y la memoria caché de segundo nivel actualizaciones) en un orden especial para que las restricciones de clave externa no pueden ser violados:

  1. inserciones, en el orden en que se realizaron
  2. Actualizaciones
  3. supresión de elementos de recogida de
  4. inserción de elementos de recogida de
  5. Borra, en el orden en que se realizaron

Al tener restricciones únicas Es muy importante conocer este orden, especialmente si desea reemplazar un niño de uno a muchos (eliminar edad/insertar nuevo), pero tanto el niño viejo como el nuevo comparten las mismas limitaciones únicas (por ejemplo, misma dirección de correo electrónico). En este caso, puede actualizar la entrada anterior, en lugar de eliminar/insertar, o puede enjuagar después de eliminar solo para luego continuar la inserción. Para un ejemplo más detallado, puede marcar this article.

Tenga en cuenta que no especifica el orden de las actualizaciones. El examen del código de Hibernate me lleva a pensar que el orden de actualización dependerá del orden en que se agregaron las entidades al contexto de persistencia, NOT en el orden en que se actualizaron. Eso podría ser predecible en su código, pero leer el código de Hibernate no me hizo sentir que confiaría en ese orden.

Hay tres soluciones que se me ocurren:

  1. intente configurar hibernate.order_updates ser cierto . Esto debería ayudar a evitar interbloqueos cuando se actualizan varias filas en la misma tabla, pero no ayudará con los interbloqueos en múltiples tablas.
  2. Realice sus transacciones con un bloqueo PESSIMISTIC_WRITE en una de las entidades antes de realizar cualquier actualización. La entidad que utilice dependerá de su situación específica, pero siempre que se asegure que una entidad se elija de forma consistente si existe un riesgo de estancamiento, esto bloqueará el resto de la transacción hasta que se pueda obtener el bloqueo.
  3. Escribe tu código para atrapar interbloqueos cuando ocurran y vuelva a intentarlo de manera sensata. El componente que gestiona el reintento de bloqueo muerto debe ubicarse fuera del límite de transacción actual. Esto se debe a que la sesión anómala debe cerrarse y la transacción asociada debe respaldarse. En this article puede encontrar un ejemplo de un AOP Aspect reintentado automático.
+1

Acepte mi disculpa porque, por alguna razón desconocida, me perdí esta respuesta antes :) Creo que el resultado de su examen en el código de Hibernate realmente da la respuesta más confiable hasta ahora. Buenas sugerencias especialmente para el punto 1 y 2 –

-1

En cuanto al primer ejemplo, este tipo de cosas se maneja por base de datos (lea más sobre niveles de aislamiento de transacciones y estrategias de bloqueo de su base de datos). Hay muchas formas diferentes de manejar esto.

En cuanto a Hibernate, javadoc a org.hibernate.event.def.AbstractFlushingEventListener.performExecutions (Eventsource) dice:

ejecutar todas las actualizaciones de SQL y la memoria caché de segundo nivel, en un orden especial para que las restricciones de clave externa no pueden ser violados:

  1. inserciones, en el orden en que se realizaron
  2. Actualizaciones Supresión de elementos de la colección
  3. la inserción de elementos de la colección
  4. Elimina, en el orden en que se realizaron

Supongo que esta es la única optimización de las consultas SQL ejecutadas que hace Hibernate. El resto de los problemas es manejado por la base de datos.

+0

Creo que la mayoría de las cosas de ejemplo NO pueden ser manejadas por la base de datos. Para el nivel de aislamiento, según entiendo, se trata más de cómo el cambio de una transacción es visible para otra. Sin embargo, incluso para el nivel de aislamiento más bajo, la escritura de dos transacciones en la misma fila todavía tendrá bloqueo. Por lo tanto, si un txn actualiza un registro A y luego B, y otro txn actualiza B graba luego A, aún creará un punto muerto. Lo mejor que un DBMS puede hacer es detectar posibles bloqueos. Estoy enterado de la orden de ejecución de SQL de Hibernate que mencionaste, pero lo que me preocupa es acerca de –

+0

el orden de actualización entre las entidades. Sería bastante sorprendente si Hibernate no está manejando eso y suponiendo que puede ser manejado por DB (que obviamente no es realista) –

+0

Oracle, por ejemplo, maneja de alguna manera los bloqueos "detecta automáticamente y resuelve interbloqueos al retroceder la declaración asociada con la transacción que detecta el punto muerto ": http://www.oracle-base.com/articles/misc/deadlocks.php.Esto probablemente causará una excepción JDBC, por lo que podría agregar alguna lógica de reintento en el manejo de código de la excepción. – Potejciak

Cuestiones relacionadas