Pregunta

EntityManager.merge() Puede insertar nuevos objetos y actualizar los existentes.

¿Por qué uno querría usar persist() (que sólo puede crear nuevos objetos)?

¿Fue útil?

Solución

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

Persiste toma una instancia de entidad, lo agrega al contexto y hace que esa instancia administrada (es decir, se realizará un seguimiento futuras actualizaciones de la entidad).

mezcla crea una nueva instancia de la entidad, copia el estado de la entidad suministrado, y hace que la nueva copia controlada. La instancia se pasa en que no será administrado (cualquier cambio que realice no serán parte de la transacción - a menos que llame combinar de nuevo).

Tal vez un ejemplo de código ayudará.

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)

Escenario 1 y 3 son más o menos equivalentes, pero hay algunas situaciones en las que te gustaría utilizar Escenario 2.

Otros consejos

persisten y se fusionan son para dos propósitos diferentes (que no son alternativas en absoluto).

(editado para ampliar la información diferencias)

persistir:

  • Insertar un nuevo registro a la base de datos
  • Coloque el objeto que el gestor de entidades.

fusión:

  • Encontrar un objeto unido con el mismo id y actualizarlo.
  • Si existe actualizar y devolver el objeto que ya está fijado.
  • Si no existe insertar el nuevo registro a la base de datos.

persistir () eficiencia:

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

persistir () semántica:

  • Se asegura de que se va a insertar y no actualizar 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 manera sólo existe 1 objeto adjunto para cualquier registro en el gestor 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;
}

A pesar de si está conectado a MySQL merge () podría ser tan eficiente como persistir () usando una llamada a INSERT opción UPDATE ON DUPLICATE KEY con, JPA es una programación de muy alto nivel y no se puede asumir que esto va a ser el caso en todas partes.

Si está utilizando el generador asignado, usando fusionar en lugar de persistir puede causar un SQL redundante comunicado, lo que afecta el rendimiento.

Además, llamando fusionan para entidades gestionadas también es un error ya que son entidades gestionadas gestiona automáticamente Hibernate y su estado está sincronizado con el registro de la base por la mecanismo de comprobación sucia sobre lavar el contexto de persistencia .

Para entender cómo funciona todo esto, primero debe saber que Hibernate cambia el modo de pensar desarrollador de sentencias SQL para transiciones de estado entidad.

Una vez que una entidad está gestionado activamente por Hibernate, todos los cambios van a ser propagado de forma automática a la base de datos.

Hibernate monitores conectados actualmente entidades. Pero para una entidad a que logró, debe estar en el estado de entidad derecha.

En primer lugar, hay que definir todos los estados de la entidad:

  • Nuevo (transitoria)

    Un objeto de nueva creación que nunca no se ha asociado con una Hibernate Session (a.k.a Persistence Context) y no se asigna a ninguna fila de la tabla de base de datos se considera que en el estado de Nueva (transitoria).

    Para convertirse en persistía necesitamos ya sea explícitamente llamar al método EntityManager#persist o hacer uso del mecanismo de persistencia transitiva.

  • persistente (Gestionado)

    Una entidad persistente ha sido asociada con una fila de la tabla de base de datos y está siendo gestionado por la corriente de funcionamiento contexto de persistencia. Cualquier cambio realizado en dicha entidad va a ser detectado y se propagó a la base de datos (durante la Sesión ras-tiempo). Con Hibernate, ya no tenemos para ejecutar sentencias INSERT / UPDATE / DELETE. Hibernate utiliza una estilo transaccional de escritura en segundo de trabajo y los cambios son sincronizada en el último momento responsable, durante el <=>-tiempo de descarga actual.

  • Independiente

    Una vez que la corriente de funcionamiento contexto de persistencia está cerrado todas las entidades gestionadas anteriormente se desprenden. Los sucesivos cambios ya no pueden seguir y no hay sincronización automática de base de datos va a suceder.

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

    • Cómo volver a colocar

      Hibernate (pero no JPA 2.1) compatible con volver a colocar a través del método de actualización Sesión #. Una sesión de Hibernate sólo puede asociar un objeto de entidad para una fila determinada base de datos. Esto es porque el contexto de persistencia actúa como una caché en memoria (primera caché nivel) y un único valor (entidad) está asociado a una tecla determinada (tipo de entidad y el identificador de base de datos). Una entidad se puede volver a colocar sólo si no hay ningún otro objeto JVM (búsqueda de la misma fila de base de datos) ya asociada a la sesión actual Hibernate.

    • La fusión

    La fusión va a copiar el estado de entidad separada (fuente) a una instancia de entidad gestionada (destino). Si la entidad fusionada no tiene equivalente en el actual período de sesiones, uno será obtienen de la base de datos. La instancia de objeto independiente seguirá siendo independiente, incluso después de la operación de fusión.

  • Se ha quitado

    A pesar de las demandas de la APP que lograron solamente entidades se les permite ser eliminado, Hibernate también puede eliminar unifamiliares entidades (pero sólo a través de una Sesión # eliminar llamada de método). Una entidad eliminado solamente está programada para su eliminación y la base de datos real DELETE se ejecutad durante la sesión en tiempo de lavado.

Para entender mejor las transiciones de estado de la APP, se puede visualizar el siguiente diagrama:

introducir descripción de la imagen aquí

O si utiliza la API específica de Hibernate:

introducir descripción de la imagen aquí

Me di cuenta de que cuando usaba em.merge, Conseguí un SELECT declaración para cada INSERT, incluso cuando no había ningún campo que JPA estuviera generando para mí: el campo de clave principal era un UUID que configuré yo mismo.me cambié a em.persist(myEntityObject) y acaba de llegar INSERT declaraciones entonces.

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

  

Si X es un objeto individual, la EntityExistsException puede ser lanzado cuando el persisten   operación es invocada, o la PersistenceException u otro @GeneratedValue puede ser lanzado a ras o cometen tiempo.

Así que usando @Id sería adecuado cuando el objeto ¿No era necesario a ser un objeto distante. Es posible que prefiera tener el código de lanzar el merge() por lo que no rápido.

la especificación es poco claras, <=> podría establecer el <=> <=> de un objeto. <=> sin embargo debe tener un objeto con el <=> ya generada.

Hay algunas diferencias más entre merge y persist (Voy a enumerar nuevamente los ya publicados aquí):

D1. merge no hace que la entidad pasada sea administrada, sino que devuelve otra instancia que sí está administrada. persist en el otro lado hará que la entidad pasada sea 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 conservarla nuevamente, puede hacerlo solo con persist(), porque merge lanzará un IllegalArgumentException.

D3.Si decidió cuidar manualmente sus ID (por ejemplo, utilizando UUID), entonces un merge La operación desencadenará posteriores SELECT consultas para buscar entidades existentes con esa ID, mientras persist Es posible que no necesite esas consultas.

D4.Hay casos en los que simplemente no confías en el código que llama a tu código, y para asegurarte de que no se actualicen datos, sino que se inserten, debes usar persist.

Algunos detalles más acerca de la combinación que le ayudará a utilizar la combinación más persisten:

  

Al regresar una instancia de gestión distinta de la entidad original es una parte crítica de la fusión   proceso. Si una instancia de entidad con el mismo identificador ya existe en el contexto de persistencia, la   proveedor se sobreponen a su estado con el estado de la entidad que se está fusionando, pero la gestión   versión que ya existía debe ser devuelto al cliente para que pueda ser utilizado. Si el proveedor no lo hizo   actualizar la instancia del empleado en el contexto de persistencia, cualquier referencia a esa instancia se convertirán   incompatibles con el nuevo estado que se pueden fusionar en.

     

Cuando merge () se invoca en una nueva entidad, se comporta de manera similar a la operación persist (). añade   la entidad para el contexto de persistencia, pero en lugar de añadir la instancia de la entidad original, se crea una nueva   copiar y gestiona esa instancia en su lugar. La copia que se crea por la operación de fusión () se conserva   como si el persisten () método se invoca en él.

     

En la presencia de relaciones, la operación de fusión () intentará actualizar la entidad gestionada   para apuntar a versiones gestionadas de las entidades referenciadas por la entidad separada. Si la entidad tiene una   relación a un objeto que no tiene identidad persistente, el resultado de la operación de fusión es   indefinido. Algunos proveedores podrían permitir la copia controlada para que apunte al objeto no persistente,   mientras que otros podrían lanzar una excepción inmediatamente. La operación de combinación () puede ser opcionalmente   en cascada en estos casos para evitar una excepción que se produzcan. Vamos a cubrir en cascada de la fusión ()   operación más adelante en esta sección. Si una entidad de ser puntos fusionadas a una entidad removida, una   será lanzada IllegalArgumentException excepción.

     

relaciones Lazy-carga son un caso especial en la operación de fusión. Si un perezoso de carga   relación no fue provocada por una entidad antes de que se desprendió, esa relación será   ignorado cuando se fusionó la entidad. Si la relación se desencadenó mientras administrado y luego se puso a cero mientras que la entidad se separó, la versión administrada de la entidad va a tener igualmente la relación despejado durante la fusión ".

Toda la información anterior fue tomado de "Pro APP 2 Dominar la API de Java ™ Persistencia" por Mike Keith y Merrick Schnicariol. Capítulo 6. Sección desprendimiento y fusión. Este libro es en realidad un segundo libro dedicado a la APP por los autores. Este nuevo libro tiene muchas nuevas informaciones a continuación anterior. Realmente recomiendo leer este libro para los que van a ser seriamente involucrados con APP. Lo siento por publicar anónimamente mi primera respuesta.

Recibía excepciones de carga diferida en mi entidad porque estaba intentando acceder a una colección cargada de forma diferida que estaba en sesión.

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

Para aliviar esto, actualicé la misma entidad en mi controlador y la pasé a mi jsp, aunque imagino que cuando vuelva a guardar en la sesión también será accesible. SessionScope y no tirar un LazyLoadingException, 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!!

Al revisar las respuestas, faltan algunos detalles sobre "Cascada" y la generación de identificación. Ver pregunta

Además, cabe mencionar que puedes tener separados Cascade anotaciones para fusionar y persistir: Cascade.MERGE y Cascade.PERSIST el cual será tratado según el método utilizado.

La especificación es tu amiga;)

He encontrado esta explicación por parte de la documentación de Hibernate esclarecedor, ya que contienen un caso de uso:

  

El uso y la semántica de merge () parece ser confuso para los nuevos usuarios. En primer lugar, siempre y cuando usted no está tratando de utilizar el estado del objeto cargado en un gestor de la entidad en otro nuevo gestor de la entidad, debe no tenga que utilizar la combinación de () en absoluto . Algunas aplicaciones enteras nunca va a usar este método.

     

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

     
      
  • La aplicación carga un objeto en el primer director de la entidad
  •   
  • el objeto se pasa hasta la capa de presentación
  •   
  • algunas modificaciones se realizan para el objeto
  •   
  • el objeto se pasa hacia abajo a la capa de lógica de negocio
  •   
  • la aplicación persiste estas modificaciones llamando merge () en un segundo gestor de la entidad
  •   
     

Esta es la semántica exacta de merge ():

     
      
  • si hay una instancia administrada con el mismo identificador actualmente asociados con el contexto de persistencia, copia el estado del objeto dado en el ejemplo gestionados
  •   
  • Si no hay una instancia administrada actualmente asociados con el contexto de persistencia, tratar de cargarlo desde la base de datos, o crear una nueva instancia logrado
  •   
  • la instancia administrada se devuelve
  •   
  • el ejemplo dado no asociado con el contexto de persistencia, sigue siendo independiente y por lo general se desecha
  •   

De: http: //docs.jboss. org / hibernación / EntityManager / 3,6 / referencia / en / html / objectstate.html

  

APP es indiscutiblemente una gran simplificación en el dominio de la empresa   aplicaciones basadas en la plataforma Java. Como un desarrollador que debía   hacer frente a las complejidades de los viejos beans de entidad en J2EE que veo la   inclusión de APP entre las especificaciones Java EE como un gran salto   adelante. Sin embargo, mientras que profundizar en los detalles de la APP Encuentro   cosas que no son tan fáciles. En este artículo me ocupo de comparación de   combinación del EntityManager y persisten los métodos cuya superposición   comportamiento puede causar confusión no sólo para un novato. Por otra parte me   proponer una generalización que ve ambos métodos como casos especiales de una   más método general combinar.

La persistencia de las entidades

En contraste con el método de combinación de la persisten método es bastante sencillo e intuitivo. El escenario más común del uso del método de persistir se puede resumir de la siguiente manera:

"Una instancia recién creada de la clase de entidad se pasa al método persistir. Después devuelve este método, la entidad es gestionado y planificado para su inserción en la base de datos. Puede ocurrir en o antes de la transacción se confirma o cuando el método flush se llama. Si la entidad hace referencia a otra entidad a través de una relación marcada con la estrategia en cascada PERSISTIR este procedimiento se aplica a ella también ".

 introducir descripción de la imagen aquí

La especificación va más en detalles, sin embargo, recordar que no es crucial, ya que estos datos cubren situaciones más o menos exóticos solamente.

entidades que se fusionan

En comparación a persistir, la descripción del comportamiento de la fusión no es tan simple. No hay ningún escenario principal, como lo es en el caso de persistir, y un programador debe recordar todos los escenarios con el fin de escribir un código correcto. Me parece que los diseñadores de la APP quería tener algún método cuya principal preocupación sería el manejo entidades separadas (como lo opuesto al método que se ocupa de entidades de nueva creación principalmente persistir.) Principal tarea del método de fusión es transferir el estado de una entidad no administrado (utilizada como argumento) a su homólogo logrado dentro del contexto de persistencia. Esta tarea, sin embargo, se divide adicionalmente en varios escenarios que empeoran la inteligibilidad de comportamiento del método global.

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:

 introducir descripción de la imagen aquí

Por lo tanto, cuando se debería utilizar cuando persisten y fusión?

persistir

  • Usted quiere que el método siempre crea una nueva entidad y nunca actualiza una entidad. De lo contrario, el método produce una excepción como consecuencia de la violación principal singularidad clave.
  • procesos
  • Batch, manipulación entidades de una manera de estado (ver patrón Gateway).
  • Optimización del rendimiento

fusionar

  • ¿Quiere el método de cualquiera de inserciones o actualizaciones una entidad en la base de datos.
  • Usted desea manejar las entidades de una manera sin estado (transferencia de datos de objetos de Servicios)
  • desea insertar una nueva entidad que pueda tener una referencia a otra entidad que pueda pero no puede ser creado todavía (relación debe estar marcado MERGE). Por ejemplo, la inserción de una nueva foto con una referencia a un nuevo o un álbum ya existente.

Escenario X:

Tabla: Spitter (uno), Tabla: spittles (Many) (spittles es propietario de la relación con un FK: spitter_id)

Este escenario da como resultado el ahorro: El Escupidor y ambos spittles como si propiedad de Same Escupidor

.
        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 ahorrará el Escupidor, salvará a los 2 spittles Pero no hará referencia a la misma Escupidor!

        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!!

Otra observación:

merge() solo se preocupará por una identificación generada automáticamente (probada en IDENTITY y SEQUENCE) cuando ya existe un registro con dicha identificación en su tabla.En ese caso merge() Intentará actualizar el registro.Sin embargo, si falta una identificación o no coincide con ningún registro existente, merge() lo ignorará por completo y le pedirá a una base de datos que asigne uno nuevo.A veces esto es una fuente de muchos errores.No utilice merge() para forzar una identificación para un nuevo registro.

persist() por otro lado, nunca te permitirá ni siquiera pasarle una identificación.Fallará inmediatamente.En mi caso es:

Causado por:org.hibernate.PersistentObjectException:entidad separada pasado a persistir

hibernate-jpa javadoc tiene una pista:

Lanza:javax.persistence.EntityExistsException - si la entidad ya existe.(Si la entidad ya existe, el EntityExistsException se puede lanzar cuando la operación persist es invocada, o la EntityExistsException u otra PersistenceException puede ser lanzado en el tiempo de descarga o confirmación.)

Es posible que haya llegado aquí para consejos sobre cuándo utilizar persistir y cuándo utilizar Combinar . Creo que depende de la situación:. ¿Qué probabilidades hay de que es necesario crear un nuevo registro y lo difícil que es para recuperar datos persistentes

Vamos a suponer que usted puede utilizar una clave / identificador natural.

  • Los datos necesita ser mantenido, pero de vez en cuando existe un registro y una actualización se pide. En este caso, usted podría intentar un persistir y si se lanza una EntityExistsException, que mirar hacia arriba y combinar los datos:

    try {EntityManager.persist (entidad)}

    catch (Exception EntityExistsException) {/ * recuperar y fusionar * /}

  • datos persistentes necesita ser actualizado, pero de vez en cuando no hay ningún registro de los datos todavía. En este caso se mira hacia arriba, y hacer una persistir si la entidad no se encuentra:

    entidad = EntityManager.find (clave);

    si (entidad == null) {EntityManager.persist (entidad); }

    else {/ * de combinación * /}

Si usted no tiene clave natural / identificador, tendrá un tiempo más difícil de averiguar si la entidad existe o no, o cómo mirar hacia arriba.

Las fusiones pueden ser tratados de dos maneras, también:

  1. Si los cambios son generalmente pequeños, aplicarlos a la entidad gestionada.
  2. Si los cambios son comunes, copiar el ID de la entidad PERSISTED, así como los datos inalterados. A continuación, llamar a EntityManager :: merge () para reemplazar el contenido de edad.

persistir (entidad) debe ser utilizado con totalmente nuevas entidades, para añadirlos a DB (si la entidad ya existe en el PP habrá tiro EntityExistsException).

Combinar (entidad) se debe utilizar, para poner de nuevo a la entidad contexto de persistencia si la entidad se separó y se cambió.

Es probable que persisten se genera instrucción SQL de inserción y combinar instrucción SQL de actualización (pero no estoy seguro).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top