2010-02-25 13 views
9

A tiene una entidad JPA que tiene un campo de marca de tiempo y se distingue por un campo de identificador complejo. Lo que necesito es actualizar la marca de tiempo en una entidad que ya ha sido almacenada, de lo contrario crear y almacenar nueva entidad con la marca de tiempo actual.Crear nueva entidad o actualizar la existente de una sola vez con JPA

Como resultado, la tarea no es tan simple como parece desde el primer momento. El problema es que en el entorno concurrente recibo una desagradable excepción "Índice único o violación de clave principal". Aquí está mi código:

// Load existing entity, if any. 
Entity e = entityManager.find(Entity.class, id); 
if (e == null) { 
    // Could not find entity with the specified id in the database, so create new one. 
    e = entityManager.merge(new Entity(id)); 
} 
// Set current time... 
e.setTimestamp(new Date()); 
// ...and finally save entity. 
entityManager.flush(); 

Tenga en cuenta que en este ejemplo identificador de la entidad no se genera en el inserto, se sabe de antemano.

Cuando dos o más de hilos de ejecutar este bloque de código en paralelo, pueden conseguir simultáneamente null de entityManager.find(Entity.class, id) llamada de método, por lo que intentarán guardar dos o más entidades, al mismo tiempo, con el mismo identificador que resulta en error .

Creo que hay pocas soluciones al problema.

  1. Claro que podría sincronizar este bloque de código con un bloqueo global para evitar el acceso simultáneo a la base de datos, pero que iba a ser la forma más eficiente?
  2. Algunas bases de datos admiten una muy útil declaración MERGE que actualiza las existentes o crea una nueva si no existe ninguna. Pero dudo que OpenJPA (implementación de JPA de mi elección) lo soporte.
  3. Evento si JPA no es compatible con SQL MERGE, siempre puedo recurrir a la antigua JDBC simple y hacer lo que quiera con la base de datos. Pero no quiero dejar API cómoda y meterme con la peluda combinación JDBC + SQL.
  4. Hay un truco de magia para arreglarlo solo con la API JPA estándar, pero todavía no lo sé.

Por favor ayuda.

Respuesta

1

Usted se refiere al aislamiento de transacción de las transacciones JPA. Es decir. cuál es el comportamiento de las transacciones cuando acceden a los recursos de otras transacciones.

Según this article:

READ_COMMITTED es el nivel de aislamiento de las transacciones se esperaba para el uso de [..] EJB3 JPA

Esto significa que - sí, usted tendrá problemas con el código anterior .

Pero JPA no admite niveles de aislamiento personalizados.

This thread discute el tema más extensamente. Dependiendo de si usa Spring o EJB, creo que puede hacer uso de la estrategia de transacción adecuada.

+0

Ambos enlaces están rotos – Sergey

Cuestiones relacionadas