2011-05-17 17 views
7

Me enfrenté a un problema. Tengo una aplicación con Hibernate que carga datos de archivos XML en tablas en modo concurrente. Alguna parte de los datos podría ser la misma y podría insertarse desde hilos de differnet. Cada hilo funciona en su propia transacción de juego largo. Hay un problema cuando dos o más pisadas intentan comprometer la transacción. Por ejemplo, dos hilos insertaron registros en la tabla Ciudad que tiene una restricción en campo NOMBRE. Significa que ConstraintViolationException se produce en flush() o commit(). Quiero manejar automáticamente estas colisiones y desear que los nuevos objetos problemáticos sean reemplazados por objetos viejos ya insertados. es posible? Veo saveOrUpdate() y el control de versión optimista en Hibernate.Hibernate inserción simultánea

+0

Hola, me alegraría si comparte su solución a ese problema. Parece que a continuación se encuentra la respuesta correcta; sin embargo, una breve explicación debería ser más conveniente. Muchas gracias. – Javatar

Respuesta

1

Supongo que usa uno de MVCC-based DBMS.

Si el nivel de aislamiento de transacción no es superior a READ COMMITTED, puede reducir la probabilidad de conflicto emitiendo una consulta para verificar la existencia de Cities con el mismo name antes de insertar el nuevo.

Tenga en cuenta que saveOrUpdate() no puede ayudar aquí, ya que name no es una clave principal. También tenga en cuenta que no puede evitar conflictos en absoluto (al menos sin utilizar algunas funciones específicas de DBMS), ya que básicamente es un ejemplo de write skew anomaly, que no se puede evitar en DBMS basado en MVCC.

Además, si la atomicidad de la importación del archivo XML no es crítica, puede dividir las transacciones largas en varias más cortas, y simplemente reintentarlas en caso de una violación de restricciones.

+0

Gracias, es una buena idea romper la transacción. Creo que verificar la existencia del objeto City no puede ayudar en un escenario concurrente. Siempre hay una posibilidad de tener una colisión. De acuerdo con saveOrUpdate() ya lo marcó. –

+0

Disculpe, ¿quiere decir usar READ UNCOMMITTED y verificar existencia? Creo que puede ayudar. Al menos los registros sin compromiso se comparten entre las transacciones y no es tan costoso hacer la comprobación de la existencia en la sesión sin compromiso. –

0

En situaciones como esta, utilizamos la convención de un método 'insertOrUpdate()' con el siguiente flujo general. La transacción se confirma por el llamador del método 'insertOrUpdate()' a su regreso:

public MyHibernateObject insertOrUpdate(MyHibernateObject newObj, Session s) { 
    String name = newObj.getCityName(); 
    MyHibernateObject existingObj = getByCityName(name, s); 
    if (existingObj == null) { 
     s.saveOrUpdate(newObj); 
     return newObj; 
    } else { 
     existing.copyImportantFields(newObj); 
     s.saveOrUpdate(existing); 
     return existing; 
    } 
} 
Cuestiones relacionadas