JPA EntityManager: ¿Por qué usar persist () sobre merge ()?

Respuestas:

1615

De cualquier manera agregará una entidad a un PersistenceContext, la diferencia está en lo que haga con la entidad después.

Persist toma una instancia de entidad, la agrega al contexto y hace que esa instancia sea administrada (es decir, se rastrearán futuras actualizaciones de la entidad).

Merge devuelve la instancia administrada a la que se fusionó el estado. Devuelve algo que existe en PersistenceContext o crea una nueva instancia de su entidad. En cualquier caso, copiará el estado de la entidad suministrada y devolverá la copia administrada. La instancia que ingrese no se administrará (los cambios que realice no formarán parte de la transacción, a menos que vuelva a llamar a fusionar). A través del uso puede devolver la instancia (administrada).

Tal vez un ejemplo de código ayude.

MyEntity e = new MyEntity();

// scenario 1
// tran starts
em.persist(e); 
e.setSomeField(someValue); 
// tran ends, and the row for someField is updated in the database

// scenario 2
// tran starts
e = new MyEntity();
em.merge(e);
e.setSomeField(anotherValue); 
// tran ends but the row for someField is not updated in the database
// (you made the changes *after* merging)

// scenario 3
// tran starts
e = new MyEntity();
MyEntity e2 = em.merge(e);
e2.setSomeField(anotherValue); 
// tran ends and the row for someField is updated
// (the changes were made to e2, not e)

Los escenarios 1 y 3 son más o menos equivalentes, pero hay algunas situaciones en las que desearía usar el escenario 2.

Miguel
fuente
3
@dma_k: Parece que estás usando Hibernate. Estoy menos familiarizado con Hibernate que JPA, pero en JPA si llama a EntityManager.persist () y pasa una entidad separada, usted: a) obtendrá una EntityExistsException inmediatamente ob) obtendrá otra PersistenceException en el momento del vaciado / confirmación. Tal vez he entendido mal la pregunta aquí?
Mike
49
Esta respuesta podría mejorarse si también cubriera los casos en los que la entidad que se fusionó / ​​persistió ya existe en el contexto persistente (o al menos dejó en claro que solo describe el comportamiento cuando la entidad persistente / fusionada ya no existe)
Henry
2
¿Es un método más eficaz? ¿Quizás mergela copia completa de un objeto antes de administrarlo tiene un impacto en el rendimiento?
Kevin Meredith
2
¿Qué hay de los identificadores? Si tengo una, @GeneratedId¿puedo obtenerla en el escenario 2?
rascio
77
Mike: "La fusión crea una nueva instancia ...": esto no siempre es cierto. Si EntityManager encuentra una entidad ya administrada en su contexto, devuelve esta instancia (después de haber actualizado los campos). Edite su respuesta, luego votaré por ella.
Heri
181

La persistencia y la fusión tienen dos propósitos diferentes (no son alternativas en absoluto).

(editado para ampliar la información de diferencias)

persistir:

  • Insertar un nuevo registro en la base de datos
  • Adjunte el objeto al administrador de la entidad.

unir:

  • Encuentre un objeto adjunto con la misma identificación y actualícelo.
  • Si existe, actualice y devuelva el objeto ya adjunto.
  • Si no existe, inserte el nuevo registro en la base de datos.

persistir () eficiencia:

  • Podría ser más eficiente para insertar un nuevo registro en una base de datos que merge ().
  • No duplica el objeto original.

persistir () semántica:

  • Se asegura de que esté insertando y no actualizando por error.

Ejemplo:

{
    AnyEntity newEntity;
    AnyEntity nonAttachedEntity;
    AnyEntity attachedEntity;

    // Create a new entity and persist it        
    newEntity = new AnyEntity();
    em.persist(newEntity);

    // Save 1 to the database at next flush
    newEntity.setValue(1);

    // Create a new entity with the same Id than the persisted one.
    AnyEntity nonAttachedEntity = new AnyEntity();
    nonAttachedEntity.setId(newEntity.getId());

    // Save 2 to the database at next flush instead of 1!!!
    nonAttachedEntity.setValue(2);
    attachedEntity = em.merge(nonAttachedEntity);

    // This condition returns true
    // merge has found the already attached object (newEntity) and returns it.
    if(attachedEntity==newEntity) {
            System.out.print("They are the same object!");
    }

    // Set 3 to value
    attachedEntity.setValue(3);
    // Really, now both are the same object. Prints 3
    System.out.println(newEntity.getValue());

    // Modify the un attached object has no effect to the entity manager
    // nor to the other objects
    nonAttachedEntity.setValue(42);
}

De esta forma solo existe 1 objeto adjunto para cualquier registro en el administrador de la entidad.

merge () para una entidad con un id es algo como:

AnyEntity myMerge(AnyEntity entityToSave) {
    AnyEntity attached = em.find(AnyEntity.class, entityToSave.getId());
    if(attached==null) {
            attached = new AnyEntity();
            em.persist(attached);
    }
    BeanUtils.copyProperties(attached, entityToSave);

    return attached;
}

Aunque si está conectado a MySQL merge () podría ser tan eficiente como persistir () usando una llamada para INSERTAR con la opción ACTUALIZACIÓN DE LLAVE DUPLICADA, JPA es una programación de muy alto nivel y no puede suponer que este será el caso en todas partes.

Josep Panadero
fuente
¿Puede usted nombrar un caso en el que no es válida para reemplazar em.persist(x)con x = em.merge(x)?
Aaron Digulla
20
persist () puede lanzar una EntityExistsException. Si desea asegurarse de que su código está haciendo una inserción y no una actualización de los datos, debe usar persistir.
Josep Panadero
1
merge()también puede lanzar unEntityExistsException
Sean
1
@Ninguno Podría porque es un RuntimeException, pero no se menciona en el Javadoc.
Martin
154

Si está utilizando el generador asignado, el uso de la combinación en lugar de persistir puede causar una instrucción SQL redundante , lo que afecta el rendimiento.

Además, la fusión de llamadas para entidades administradas también es un error, ya que las entidades administradas son administradas automáticamente por Hibernate y su estado se sincroniza con el registro de la base de datos mediante el mecanismo de verificación sucio al vaciar el Contexto de persistencia .

Para comprender cómo funciona todo esto, primero debe saber que Hibernate cambia la mentalidad del desarrollador de las declaraciones SQL a las transiciones de estado de entidad .

Una vez que Hibernate gestione activamente una entidad, todos los cambios se propagarán automáticamente a la base de datos.

Hibernate supervisa las entidades actualmente conectadas. Pero para que una entidad se gestione, debe estar en el estado de entidad correcto.

Para comprender mejor las transiciones de estado JPA, puede visualizar el siguiente diagrama:

Transiciones de estado de entidad JPA

O si usa la API específica de Hibernate:

Transiciones de estado de entidad hibernada

Como se ilustra en los diagramas anteriores, una entidad puede estar en uno de los siguientes cuatro estados:

  • Nuevo (transitorio)

    Se considera que un objeto recién creado que nunca se ha asociado con un Hibernate Session(aka Persistence Context) y que no está asignado a ninguna fila de la tabla de la base de datos está en el estado Nuevo (Transitorio).

    Para ser persistente, necesitamos llamar explícitamente el EntityManager#persistmétodo o hacer uso del mecanismo de persistencia transitiva.

  • Persistente (Gestionado)

    Una entidad persistente se ha asociado con una fila de la tabla de la base de datos y está siendo administrada por el Contexto de persistencia actualmente en ejecución. Cualquier cambio realizado en dicha entidad se detectará y propagará a la base de datos (durante el tiempo de descarga de la sesión). Con Hibernate, ya no tenemos que ejecutar las instrucciones INSERT / UPDATE / DELETE. Hibernate emplea un estilo de trabajo transaccional de reescritura y los cambios se sincronizan en el último momento responsable, durante el Sessiontiempo de descarga actual .

  • Separado

    Una vez que el contexto de persistencia actualmente en ejecución se cierra, todas las entidades administradas previamente se separan. Los cambios sucesivos ya no se rastrearán y no se realizará una sincronización automática de la base de datos.

    Para asociar una entidad separada a una sesión de Hibernate activa, puede elegir una de las siguientes opciones:

    • Volver a colocar

      Hibernate (pero no JPA 2.1) admite la reconexión a través del método de actualización Session #. Una sesión de Hibernate solo puede asociar un objeto de entidad para una fila de base de datos determinada. Esto se debe a que el contexto de persistencia actúa como un caché en memoria (caché de primer nivel) y solo un valor (entidad) está asociado con una clave dada (tipo de entidad e identificador de base de datos). Una entidad se puede volver a unir solo si no hay otro objeto JVM (que coincida con la misma fila de la base de datos) ya asociado con la sesión de Hibernate actual.

    • Fusionando

    La fusión va a copiar el estado de la entidad separada (fuente) en una instancia de entidad administrada (destino). Si la entidad fusionada no tiene equivalente en la sesión actual, se obtendrá una de la base de datos. La instancia del objeto separado continuará estando separada incluso después de la operación de fusión.

  • Remoto

    Aunque JPA exige que solo se permita eliminar las entidades administradas, Hibernate también puede eliminar entidades separadas (pero solo a través de una llamada al método de eliminación de sesión #). Una entidad eliminada solo se programa para su eliminación y la instrucción DELETE de la base de datos real se ejecutará durante el tiempo de descarga de la sesión.

Vlad Mihalcea
fuente
¿Puedes echar un vistazo stackoverflow.com/questions/46214322/… ?
gstackoverflow
@gstackoverflow La respuesta que obtuvo es la correcta. Para obtener más detalles, consulte este artículo o mi libro, High-Performance Java Persistence .
Vlad Mihalcea
Por lo tanto, no hay posibilidad de cambiar el orden de operación para huérfano = verdadero?
gstackoverflow
Su artículo sobre orden de operación en el caso habitual Mi pregunta específica para OrphanRemoval
gstackoverflow
1
El hecho es que es imposible explicar la hibernación con un diagrama como ese. ¿Por qué no puedes tirar la sesión después de despegar? ¿Qué sucede cuando intentas guardar una entidad ya persistente? ¿Por qué ese comportamiento de descarga es diferente cuando se trata de guardar y persistir? Hay 1000 preguntas de este tipo, para las cuales nadie tiene una lógica clara.
GingerBeer
37

Me di cuenta de que cuando lo usaba em.merge, recibía una SELECTdeclaración para cada INSERT, incluso cuando no había ningún campo que JPA generara para mí: el campo de clave principal era un UUID que configuré yo mismo. Cambié a em.persist(myEntityObject)y obtuve solo INSERTdeclaraciones entonces.

Sarah Vessels
fuente
3
Tiene sentido ya que asigna las ID y el contenedor JPA no tiene idea de dónde lo obtuvo. Existe la posibilidad (pequeña) de que el objeto ya exista en la base de datos, por ejemplo, en un escenario donde varias aplicaciones escriben en la misma base de datos.
Aaron Digulla
Me he enfrentado a un problema similar con merge(). Tenía una base de datos PostgreSQL con una vista complicada : la vista agregaba datos de varias tablas (las tablas tenían una estructura idéntica pero nombres diferentes). Así que JPA intentó hacerlo merge(), pero en realidad JPA se creó primero SELECT(la base de datos debido a la configuración de visualización podría devolver varios registros con la misma clave primaria de diferentes tablas), luego JPA (Hibernate fue una implementación) falló: hay varios registros con la misma clave ( org.hibernate.HibernateException: More than one row with the given identifier was found) En mi caso persist()me ayudó.
flaz14
29

La especificación JPA dice lo siguiente sobre persist().

Si X es un objeto separado, EntityExistsExceptionse puede lanzar cuando se invoca la operación de persistencia, o se puede lanzar el EntityExistsExceptionu otro PersistenceExceptionen el momento de vaciado o confirmación.

Por persist()lo tanto, el uso sería adecuado cuando el objeto no debería ser un objeto separado. Es posible que prefiera que el código arroje el código PersistenceExceptionpara que falle rápidamente.

Aunque la especificación no está clara , persist()podría establecer el@GeneratedValue @Id para un objeto. merge()sin embargo debe tener un objeto con el @Idya generado.

Raedwald
fuente
55
1 para " merge()sin embargo debe tener un objeto con el @Id ya generado . ". Cada vez que el EntityManager no encuentra un valor para el campo de ID del objeto, persiste (se inserta) en la base de datos.
Omar
No entendí esto primero, ya que no tenía claro los estados. Espero que esto ayude a alguien como lo hizo para mí. docs.jboss.org/hibernate/core/3.6/reference/en-US/html/…
RBz
1
@GeneratedValue no tiene una implicación diferente para merge () y persistir ()
SandeepGodara
17

Algunos detalles más sobre la fusión que le ayudarán a usar la fusión persisten:

Devolver una instancia administrada que no sea la entidad original es una parte crítica del proceso de fusión. Si ya existe una instancia de entidad con el mismo identificador en el contexto de persistencia, el proveedor sobrescribirá su estado con el estado de la entidad que se está fusionando, pero la versión administrada que ya existía debe devolverse al cliente para que pueda ser usado. Si el proveedor no actualizó la instancia de Employee en el contexto de persistencia, cualquier referencia a esa instancia será inconsistente con el nuevo estado que se está fusionando.

Cuando se invoca merge () en una nueva entidad, se comporta de manera similar a la operación persist (). Agrega la entidad al contexto de persistencia, pero en lugar de agregar la instancia de entidad original, crea una nueva copia y administra esa instancia en su lugar. La copia creada por la operación merge () se conserva como si se invocara el método persist ().

En presencia de relaciones, la operación merge () intentará actualizar la entidad administrada para que apunte a las versiones administradas de las entidades a las que hace referencia la entidad separada. Si la entidad tiene una relación con un objeto que no tiene identidad persistente, el resultado de la operación de fusión no está definido. Algunos proveedores pueden permitir que la copia administrada apunte al objeto no persistente, mientras que otros pueden lanzar una excepción de inmediato. La operación merge () se puede en cascada opcionalmente en estos casos para evitar que ocurra una excepción. Cubriremos la cascada de la operación merge () más adelante en esta sección. Si una entidad que se fusiona apunta a una entidad eliminada, se generará una excepción IllegalArgumentException.

Las relaciones de carga diferida son un caso especial en la operación de fusión. Si no se activó una relación de carga diferida en una entidad antes de que se separara, esa relación se ignorará cuando se fusione la entidad. Si la relación se desencadenó mientras se administraba y luego se estableció como nula mientras la entidad se desconectaba, la versión administrada de la entidad también tendrá la relación despejada durante la fusión ".

Mike Keith y Merrick Schnicariol tomaron toda la información anterior de "Pro JPA 2 Mastering the Java ™ Persistence API". Capítulo 6. Desprendimiento y fusión de secciones. Este libro es en realidad un segundo libro dedicado a JPA por los autores. Este nuevo libro tiene mucha información nueva que la anterior. Realmente recomiendo leer este libro para aquellos que estarán seriamente involucrados con JPA. Lamento haber publicado mi primera respuesta de forma anónima.

Khurshed Salimov
fuente
17

Hay algunas diferencias más entre mergeypersist (enumeraré nuevamente las que ya se publicaron aquí):

D1 mergeno hace que la entidad pasada sea administrada, sino que devuelve otra instancia que se administra. persistPor otro lado, la entidad aprobada será administrada:

//MERGE: passedEntity remains unmanaged, but newEntity will be managed
Entity newEntity = em.merge(passedEntity);

//PERSIST: passedEntity will be managed after this
em.persist(passedEntity);

D2 Si elimina una entidad y luego decide persistirla, puede hacerlo solo con persist (), porque mergearrojará un IllegalArgumentException.

D3 Si decidió cuidar sus ID manualmente (por ejemplo, mediante UUID), una merge operación activará SELECTconsultas posteriores para buscar entidades existentes con esa ID, mientraspersist puede que no necesite esas consultas.

D4 Hay casos en los que simplemente no confía en el código que llama a su código, y para asegurarse de que no se actualizan datos, sino que se insertan, debe usarlos persist.

Andrei I
fuente
8

Estaba recibiendo excepciones de lazyLoading en mi entidad porque estaba tratando de acceder a una colección con carga diferida que estaba en sesión.

Lo que haría sería en una solicitud por separado, recuperar la entidad de la sesión y luego intentar acceder a una colección en mi página jsp que era problemática.

Para aliviar esto, actualicé la misma entidad en mi controlador y la pasé a mi jsp, aunque imagino cuando volví a guardar en la sesión que también será accesible SessionScopey no arrojará unLazyLoadingException una modificación del ejemplo 2:

Lo siguiente me ha funcionado:

// scenario 2 MY WAY
// tran starts
e = new MyEntity();
e = em.merge(e); // re-assign to the same entity "e"

//access e from jsp and it will work dandy!!
jugador logix
fuente
7

Encontré esta explicación de los documentos de Hibernate esclarecedores, porque contienen un caso de uso:

El uso y la semántica de merge () parece ser confuso para los nuevos usuarios. En primer lugar, siempre que no intente utilizar el estado del objeto cargado en un administrador de entidades en otro nuevo administrador de entidades, no debería necesitar utilizar merge () . Algunas aplicaciones completas nunca usarán este método.

Por lo general, merge () se usa en el siguiente escenario:

  • La aplicación carga un objeto en el primer administrador de entidades
  • el objeto se pasa a la capa de presentación
  • se hacen algunas modificaciones al objeto
  • el objeto se devuelve a la capa de lógica de negocios
  • la aplicación persiste en estas modificaciones llamando a merge () en un segundo administrador de entidades

Aquí está la semántica exacta de merge ():

  • Si hay una instancia administrada con el mismo identificador actualmente asociado con el contexto de persistencia, copie el estado del objeto dado en la instancia administrada
  • Si no hay una instancia administrada actualmente asociada con el contexto de persistencia, intente cargarla desde la base de datos o cree una nueva instancia administrada
  • se devuelve la instancia gestionada
  • la instancia dada no se asocia con el contexto de persistencia, permanece separada y generalmente se descarta

De: http://docs.jboss.org/hibernate/entitymanager/3.6/reference/en/html/objectstate.html

Ray Hulha
fuente
6

Revisando las respuestas faltan algunos detalles sobre 'Cascade' y la generación de id. Ver pregunta

Además, vale la pena mencionar que puede tener Cascadeanotaciones separadas para fusionar y persistir:Cascade.MERGE yCascade.PERSIST que se tratarán de acuerdo con el método utilizado.

La especificación es tu amiga;)

Ioannis Deligiannis
fuente
6

JPA es indiscutiblemente una gran simplificación en el dominio de las aplicaciones empresariales creadas en la plataforma Java. Como desarrollador que tuvo que hacer frente a las complejidades de los antiguos beans de entidad en J2EE, veo la inclusión de JPA entre las especificaciones Java EE como un gran avance. Sin embargo, mientras profundizo en los detalles de JPA, encuentro cosas que no son tan fáciles. En este artículo, trato con la comparación de los métodos de fusión y persistencia de EntityManager cuyo comportamiento superpuesto puede causar confusión no solo a un novato. Además, propongo una generalización que vea ambos métodos como casos especiales de un método más general combinado.

Entidades persistentes

A diferencia del método de fusión, el método de persistencia es bastante sencillo e intuitivo. El escenario más común del uso del método persistente se puede resumir de la siguiente manera:

"Una instancia recién creada de la clase de entidad se pasa al método de persistencia. Después de que este método regrese, la entidad se administra y se planifica para su inserción en la base de datos. Puede suceder en o antes de que se confirme la transacción o cuando se llama al método de vaciado. Si la entidad hace referencia a otra entidad a través de una relación marcada con la estrategia en cascada PERSIST, este procedimiento también se aplica a ella ".

ingrese la descripción de la imagen aquí

La especificación entra más en detalles, sin embargo, recordarlos no es crucial ya que estos detalles cubren situaciones más o menos exóticas solamente.

Entidades fusionadas

En comparación con persistir, la descripción del comportamiento de la fusión no es tan simple. No hay un escenario principal, como es el caso de persistir, y un programador debe recordar todos los escenarios para escribir un código correcto. Me parece que los diseñadores de JPA querían tener algún método cuya preocupación principal sería manejar entidades separadas (como lo opuesto al método persistente que trata principalmente con entidades recién creadas). La tarea principal del método de fusión es transferir el estado de un entidad no administrada (pasada como argumento) a su contraparte administrada dentro del contexto de persistencia. Sin embargo, esta tarea se divide aún más en varios escenarios que empeoran la inteligibilidad del comportamiento general del método.

En lugar de repetir párrafos de la especificación JPA, he preparado un diagrama de flujo que representa esquemáticamente el comportamiento del método de fusión:

ingrese la descripción de la imagen aquí

Entonces, ¿cuándo debo usar persistir y cuándo fusionar?

persistir

  • Desea que el método siempre cree una nueva entidad y nunca actualice una entidad. De lo contrario, el método arroja una excepción como consecuencia de la violación de la unicidad de la clave primaria.
  • Procesos por lotes, manejo de entidades de manera con estado (ver Patrón de puerta de enlace)
  • Optimización del rendimiento

unir

  • Desea que el método inserte o actualice una entidad en la base de datos.
  • Desea manejar entidades de forma sin estado (objetos de transferencia de datos en servicios)
  • Desea insertar una nueva entidad que puede tener una referencia a otra entidad que puede pero que aún no se ha creado (la relación debe estar marcada como MERGE). Por ejemplo, insertando una nueva foto con una referencia a un álbum nuevo o preexistente.
Amit Gujarathi
fuente
¿Cuál es la diferencia entre E es administrado y PC contiene una versión administrada de E?
GingerBeer
5

Escenario X:

Tabla: Spitter (Uno), Tabla: Spittles (Muchos) (Spittles es el propietario de la relación con un FK: spitter_id)

Este escenario da como resultado el ahorro: el Spitter y ambos Spittles como si fueran propiedad de Same Spitter.

        Spitter spitter=new Spitter();  
    Spittle spittle3=new Spittle();     
    spitter.setUsername("George");
    spitter.setPassword("test1234");
    spittle3.setSpittle("I love java 2");       
    spittle3.setSpitter(spitter);               
    dao.addSpittle(spittle3); // <--persist     
    Spittle spittle=new Spittle();
    spittle.setSpittle("I love java");
    spittle.setSpitter(spitter);        
    dao.saveSpittle(spittle); //<-- merge!!

Escenario Y:

Esto salvará al Spitter, salvará a los 2 Spittles ¡Pero no harán referencia al mismo Spitter!

        Spitter spitter=new Spitter();  
    Spittle spittle3=new Spittle();     
    spitter.setUsername("George");
    spitter.setPassword("test1234");
    spittle3.setSpittle("I love java 2");       
    spittle3.setSpitter(spitter);               
    dao.save(spittle3); // <--merge!!       
    Spittle spittle=new Spittle();
    spittle.setSpittle("I love java");
    spittle.setSpitter(spitter);        
    dao.saveSpittle(spittle); //<-- merge!!
George Papatheodorou
fuente
1
El spitter es un objeto tomado del libro "Spring in Action" tercera edición de Graig Walls. Spitters son personas que dicen algo y su Spittle es lo que realmente están diciendo. Entonces, un Spitter tiene muchos spittles, lo que significa que tiene una lista de Strings.
George Papatheodorou
1
Podrías haber usado un ejemplo que sea un poco más legible sin leer Spring in Action ...
wonderb0lt
1
En realidad, no necesita saber qué es una saliva o una saliva ya que en la parte superior está escrito que Spitter es una mesa, la saliva es otra mesa que posee ... esto y aquello ...
George Papatheodorou
3

Otra observación:

merge()solo se preocupará por una identificación generada automáticamente (probada en IDENTITYy SEQUENCE) cuando ya exista un registro con dicha identificación en su tabla. En ese caso merge()intentaremos actualizar el registro. Sin embargo, si una identificación está ausente o no coincide con ningún registro existente, la merge()ignorará por completo y le pedirá a un db que asigne uno nuevo. Esto es a veces una fuente de muchos errores. No lo use merge()para forzar una identificación para un nuevo registro.

persist()por otro lado, nunca te dejará pasarle una identificación. Fallará de inmediato. En mi caso, es:

Causado por: org.hibernate.PersistentObjectException: entidad separada pasada para persistir

hibernate-jpa javadoc tiene una pista:

Emite : javax.persistence.EntityExistsException - si la entidad ya existe. (Si la entidad ya existe, se puede lanzar EntityExistsException cuando se invoca la operación de persistencia, o se puede lanzar EntityExistsException u otra PersistenceException en el momento de vaciado o confirmación).

yuranos
fuente
2
Si no está utilizando ID generadas automáticamente, tendría que darle manualmente una ID a su nueva entidad. persist()no se quejará de que tiene una ID, solo se queja cuando algo con la misma ID ya está en la base de datos.
horas
1

Es posible que haya venido aquí para obtener consejos sobre cuándo usar Persist y cuándo usar Merge . Creo que depende de la situación: qué tan probable es que necesite crear un nuevo registro y qué tan difícil es recuperar datos persistentes.

Supongamos que puede usar una clave / identificador natural.

  • Los datos deben ser persistentes, pero de vez en cuando existe un registro y se requiere una actualización. En este caso, podría intentar una persistencia y si arroja una EntityExistsException, la busca y combina los datos:

    pruebe {entityManager.persist (entidad)}

    catch (excepción EntityExistsException) {/ * recuperar y fusionar * /}

  • Los datos persistentes deben actualizarse, pero de vez en cuando todavía no hay registros de los datos. En este caso, lo busca y hace una persistencia si falta la entidad:

    entidad = entityManager.find (clave);

    if (entidad == nulo) {entityManager.persist (entidad); }

    más {/ * fusionar * /}

Si no tiene una clave / identificador natural, tendrá más dificultades para determinar si la entidad existe o no, o cómo buscarla.

Las fusiones también pueden tratarse de dos maneras:

  1. Si los cambios suelen ser pequeños, aplíquelos a la entidad administrada.
  2. Si los cambios son comunes, copie el ID de la entidad persistente, así como los datos no alterados. Luego llame a EntityManager :: merge () para reemplazar el contenido anterior.
Peter Willems
fuente
0

persist (entity) debe usarse con entidades totalmente nuevas, para agregarlas a DB (si la entidad ya existe en DB habrá EntityExistsException throw).

se debe usar merge (entidad) para volver a colocar la entidad en el contexto de persistencia si la entidad se separó y se modificó.

Probablemente persista está generando la instrucción INSERT sql y combina la instrucción UPDATE sql (pero no estoy seguro).

Krystian
fuente
Esto es incorrecto. Si llama a fusionar (e) en una nueva e, debe persistir.
Pedro Lamarão
De la especificación JPA versión 2.1, sección 3.2.7.1, segundo punto: "Si X es una nueva instancia de entidad, se crea una nueva instancia de entidad gestionada X 'y el estado de X se copia en la nueva instancia de entidad gestionada X'".
Pedro Lamarão