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.
- 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?
- 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. - 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.
- Hay un truco de magia para arreglarlo solo con la API JPA estándar, pero todavía no lo sé.
Por favor ayuda.
Ambos enlaces están rotos – Sergey