EntityManager.merge()
puede insertar nuevos objetos y actualizar los existentes.
¿Por qué uno querría usar persist()
(que solo puede crear nuevos objetos)?
jpa
merge
entitymanager
persist
java-persistence-api
Aaron Digulla
fuente
fuente
Respuestas:
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.
Los escenarios 1 y 3 son más o menos equivalentes, pero hay algunas situaciones en las que desearía usar el escenario 2.
fuente
merge
la copia completa de un objeto antes de administrarlo tiene un impacto en el rendimiento?@GeneratedId
¿puedo obtenerla en el escenario 2?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:
unir:
persistir () eficiencia:
persistir () semántica:
Ejemplo:
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:
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.
fuente
em.persist(x)
conx = em.merge(x)
?merge()
también puede lanzar unEntityExistsException
RuntimeException
, pero no se menciona en el Javadoc.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:
O si usa la API específica de Hibernate:
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
(akaPersistence 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#persist
mé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
Session
tiempo 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.
fuente
Me di cuenta de que cuando lo usaba
em.merge
, recibía unaSELECT
declaración para cadaINSERT
, 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é aem.persist(myEntityObject)
y obtuve soloINSERT
declaraciones entonces.fuente
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ó hacerlomerge()
, pero en realidad JPA se creó primeroSELECT
(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 casopersist()
me ayudó.La especificación JPA dice lo siguiente sobre
persist()
.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ódigoPersistenceException
para 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@Id
ya generado.fuente
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.Algunos detalles más sobre la fusión que le ayudarán a usar la fusión persisten:
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.
fuente
Hay algunas diferencias más entre
merge
ypersist
(enumeraré nuevamente las que ya se publicaron aquí):D1
merge
no hace que la entidad pasada sea administrada, sino que devuelve otra instancia que se administra.persist
Por otro lado, la entidad aprobada será administrada:D2 Si elimina una entidad y luego decide persistirla, puede hacerlo solo con persist (), porque
merge
arrojará unIllegalArgumentException
.D3 Si decidió cuidar sus ID manualmente (por ejemplo, mediante UUID), una
merge
operación activaráSELECT
consultas 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
.fuente
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
SessionScope
y no arrojará unLazyLoadingException
una modificación del ejemplo 2:Lo siguiente me ha funcionado:
fuente
Encontré esta explicación de los documentos de Hibernate esclarecedores, porque contienen un caso de uso:
De: http://docs.jboss.org/hibernate/entitymanager/3.6/reference/en/html/objectstate.html
fuente
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
Cascade
anotaciones 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;)
fuente
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 ".
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:
Entonces, ¿cuándo debo usar persistir y cuándo fusionar?
persistir
unir
fuente
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.
Escenario Y:
Esto salvará al Spitter, salvará a los 2 Spittles ¡Pero no harán referencia al mismo Spitter!
fuente
Otra observación:
merge()
solo se preocupará por una identificación generada automáticamente (probada enIDENTITY
ySEQUENCE
) cuando ya exista un registro con dicha identificación en su tabla. En ese casomerge()
intentaremos actualizar el registro. Sin embargo, si una identificación está ausente o no coincide con ningún registro existente, lamerge()
ignorará por completo y le pedirá a un db que asigne uno nuevo. Esto es a veces una fuente de muchos errores. No lo usemerge()
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:hibernate-jpa javadoc tiene una pista:
fuente
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.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:
fuente
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).
fuente