¿Cuáles son las diferencias entre los diferentes métodos de ahorro en Hibernate?
-
03-07-2019 - |
Pregunta
Hibernate tiene varios métodos que, de una forma u otra, toman su objeto y lo colocan en la base de datos. ¿Cuáles son las diferencias entre ellos, cuándo usar cuál y por qué no hay un solo método inteligente que sepa cuándo usar qué?
Los métodos que he identificado hasta ahora son:
save()
update()
saveOrUpdate()
saveOrUpdateCopy()
merge()
persist()
Solución
Aquí tengo mi comprensión de los métodos. Principalmente, estos se basan en la API , aunque como lo hago No utilice todos estos en la práctica.
saveOrUpdate Las llamadas guardan o actualizan dependiendo de algunas verificaciones. P.ej. Si no existe un identificador, se llama guardar. De lo contrario se llama actualización.
guardar Persiste una entidad. Asignará un identificador si no existe uno. Si uno lo hace, esencialmente está haciendo una actualización. Devuelve el ID generado de la entidad.
actualización Intenta persistir la entidad utilizando un identificador existente. Si no existe un identificador, creo que se produce una excepción.
saveOrUpdateCopy Esto está en desuso y ya no debe usarse. En cambio hay ...
fusionar Ahora aquí es donde mi conocimiento comienza a flaquear. Lo importante aquí es la diferencia entre entidades transitorias, separadas y persistentes. Para obtener más información sobre los estados de los objetos, eche un vistazo aquí . Con guardar & amp; Actualización, estás tratando con objetos persistentes. Están vinculados a una sesión para que Hibernate sepa lo que ha cambiado. Pero cuando tienes un objeto transitorio, no hay sesión involucrada. En estos casos, debe usar la combinación para actualizaciones y persistir para guardar.
persistir Como se mencionó anteriormente, esto se usa en objetos transitorios. No devuelve la ID generada.
Otros consejos
╔══════════════╦═══════════════════════════════╦════════════════════════════════╗
║ METHOD ║ TRANSIENT ║ DETACHED ║
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
║ ║ sets id if doesn't ║ sets new id even if object ║
║ save() ║ exist, persists to db, ║ already has it, persists ║
║ ║ returns attached object ║ to DB, returns attached object ║
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
║ ║ sets id on object ║ throws ║
║ persist() ║ persists object to DB ║ PersistenceException ║
║ ║ ║ ║
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
║ ║ ║ ║
║ update() ║ Exception ║ persists and reattaches ║
║ ║ ║ ║
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
║ ║ copy the state of object in ║ copy the state of obj in ║
║ merge() ║ DB, doesn't attach it, ║ DB, doesn't attach it, ║
║ ║ returns attached object ║ returns attached object ║
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
║ ║ ║ ║
║saveOrUpdate()║ as save() ║ as update() ║
║ ║ ║ ║
╚══════════════╩═══════════════════════════════╩════════════════════════════════╝
-
Consulte Hibernate Forum para Una explicación de las diferencias sutiles entre persistir y guardar. Parece que la diferencia es la hora en que se ejecuta la instrucción INSERT. Como guardar devuelve el identificador, la instrucción INSERT debe ejecutarse instantáneamente independientemente del estado de la transacción (lo que generalmente es algo malo). Persistir no ejecutará ninguna declaración fuera de la transacción actualmente en ejecución solo para asignar el identificador. Guardar / Persistir funciona tanto en instancias transitorias , es decir, instancias que todavía no tienen un identificador asignado y, como tal, no se guardan en la base de datos.
Actualizar y Combinar ambos funcionan en instancias desconectadas , es decir, instancias que tienen una entrada correspondiente en el DB pero que actualmente están no adjunto a (o gestionado por) una sesión. La diferencia entre ellos es lo que sucede con la instancia que se pasa a la función. actualizar intenta volver a vincular la instancia, lo que significa que puede que no haya otra instancia de la entidad persistente adjunta a la sesión en este momento, de lo contrario se lanzará una excepción. fusionar , sin embargo, solo copia todos los valores a una instancia persistente en la sesión (que se cargará si no está cargada actualmente). El objeto de entrada no se cambia. Entonces, fusionar es más general que actualizar , pero puede usar más recursos.
Este enlace explica de buena manera:
http://www.stevideter.com/2008/12/ 07 / saveorupdate-versus-merge-in-hibernate /
Todos tenemos esos problemas con los que nos encontramos con la misma frecuencia que cuando los volvemos a ver, sabemos que hemos resuelto esto, pero no podemos recordar cómo.
La excepción NonUniqueObjectException que se produce al usar Session.saveOrUpdate () en Hibernate es una de las mías. Estaré agregando nuevas funcionalidades a una aplicación compleja. Todas mis pruebas unitarias funcionan bien. Luego, al probar la interfaz de usuario, al intentar guardar un objeto, comienzo a recibir una excepción con el mensaje & # 8220; un objeto diferente con el mismo valor de identificador ya estaba asociado con la sesión. & # 8221; Aquí & # 8217; s un código de ejemplo de Java Persistence with Hibernate.
Session session = sessionFactory1.openSession();
Transaction tx = session.beginTransaction();
Item item = (Item) session.get(Item.class, new Long(1234));
tx.commit();
session.close(); // end of first session, item is detached
item.getId(); // The database identity is "1234"
item.setDescription("my new description");
Session session2 = sessionFactory.openSession();
Transaction tx2 = session2.beginTransaction();
Item item2 = (Item) session2.get(Item.class, new Long(1234));
session2.update(item); // Throws NonUniqueObjectException
tx2.commit();
session2.close();
Para comprender la causa de esta excepción, es importante entender los objetos separados y lo que sucede cuando llama a saveOrUpdate () (o simplemente actualiza ()) en un objeto separado.
Cuando cerramos una sesión de hibernación individual, los objetos persistentes con los que estamos trabajando se separan. Esto significa que los datos todavía están en la memoria de la aplicación, pero Hibernate ya no es responsable de rastrear los cambios en los objetos.
Si luego modificamos nuestro objeto separado y queremos actualizarlo, tenemos que volver a adjuntar el objeto. Durante ese proceso de reinstalación, Hibernate verificará si hay otras copias del mismo objeto. Si encuentra alguno, tiene que decirnos que no sabe qué es lo real # 8220; La copia es más. Quizás se hicieron otros cambios a esas otras copias que esperamos que se guarden, pero Hibernate no las conoce, porque no se las estaba administrando en ese momento.
En lugar de guardar datos posiblemente malos, Hibernate nos informa sobre el problema a través de NonUniqueObjectException.
Entonces, ¿qué debemos hacer? En Hibernate 3, tenemos merge () (en Hibernate 2, use saveOrUpdateCopy ()). Este método obligará a Hibernate a copiar cualquier cambio de otras instancias separadas en la instancia que desea guardar y, por lo tanto, fusiona todos los cambios en la memoria antes de guardar.
Session session = sessionFactory1.openSession();
Transaction tx = session.beginTransaction();
Item item = (Item) session.get(Item.class, new Long(1234));
tx.commit();
session.close(); // end of first session, item is detached
item.getId(); // The database identity is "1234"
item.setDescription("my new description");
Session session2 = sessionFactory.openSession();
Transaction tx2 = session2.beginTransaction();
Item item2 = (Item) session2.get(Item.class, new Long(1234));
Item item3 = session2.merge(item); // Success!
tx2.commit();
session2.close();
Es importante tener en cuenta que la fusión devuelve una referencia a la versión recién actualizada de la instancia. No se trata de volver a colocar el elemento en la sesión. Si prueba, por ejemplo, la igualdad (item == item3), encontrará que en este caso devuelve falso. Probablemente querrá trabajar con item3 a partir de este punto.
También es importante tener en cuenta que la API de persistencia de Java (JPA) no tiene un concepto de objetos separados y reenganchados, y utiliza EntityManager.persist () y EntityManager.merge ().
He encontrado en general que cuando uso Hibernate, saveOrUpdate () suele ser suficiente para mis necesidades. Por lo general, solo necesito usar la combinación cuando tengo objetos que pueden tener referencias a objetos del mismo tipo. Más recientemente, la causa de la excepción estaba en el código que validaba que la referencia no era recursiva. Estaba cargando el mismo objeto en mi sesión como parte de la validación, causando el error.
¿Dónde has encontrado este problema? ¿La fusión funcionó para usted o necesitaba otra solución? ¿Prefiere usar siempre la combinación o prefiere usarla solo cuando sea necesario para casos específicos?
En realidad, la diferencia entre los métodos save ()
y persist ()
de hibernación depende de la clase de generador que estemos usando.
Si nuestra clase de generador está asignada, entonces no hay diferencia entre los métodos save ()
y persist (
). Debido a que el generador & # 8216; asignó & # 8217; significa que, como programador, necesitamos dar el valor clave principal para guardar en la base de datos correctamente [Espero que conozcas este concepto de generadores]
En el caso de una clase de generador diferente a la asignada, suponga que si nuestro nombre de clase de generador es Incremento significa que hibernar por sí mismo asignará el valor de ID de clave primaria en el derecho de la base de datos [distinto del generador asignado, hibernación solo se utiliza para cuidar el valor de ID de clave primaria recordado ], por lo tanto, en este caso, si llamamos al método save ()
o persist ()
, entonces insertará el registro en la base de datos normalmente.
Pero lo importante es que el método save ()
puede devolver ese valor de ID de clave principal generado por hibernación y podemos verlo por
long s = session.save(k);
En este mismo caso, persist ()
nunca devolverá ningún valor al cliente.
Encontré un buen ejemplo que muestra las diferencias entre todos los métodos de guardado de hibernación:
En resumen, según el enlace anterior:
save()
- Podemos invocar este método fuera de una transacción. Si usamos esto sin transacciones y tenemos una conexión en cascada entre entidades, entonces solo se guarda la entidad primaria a menos que eliminemos la sesión.
- Entonces, si hay otros objetos asignados desde el objeto principal, se guardan al momento de confirmar la transacción o cuando eliminamos la sesión.
persist()
- Es similar a usar save () en la transacción, por lo que es seguro y se ocupa de cualquier objeto en cascada.
saveOrUpdate()
-
Se puede usar con o sin la transacción, y al igual que save (), si se usa sin la transacción, las entidades asignadas no se guardarán una vez que eliminemos la sesión.
-
Resultados en consultas de inserción o actualización basadas en los datos proporcionados. Si los datos están presentes en la base de datos, se ejecuta la consulta de actualización.
update()
- La actualización de Hibernate debe usarse cuando sabemos que solo estamos actualizando la información de la entidad. Esta operación agrega el objeto de entidad al contexto persistente y los cambios adicionales se rastrean y guardan cuando se confirma la transacción.
- Por lo tanto, incluso después de llamar a update, si establecemos algún valor en la entidad, se actualizarán cuando se confirme la transacción.
merge()
- La combinación de hibernación se puede usar para actualizar los valores existentes, sin embargo, este método crea una copia del objeto de entidad pasado y lo devuelve. El objeto devuelto forma parte del contexto persistente y se realiza un seguimiento de los cambios, no se realiza un seguimiento del objeto pasado. Esta es la principal diferencia con merge () de todos los demás métodos.
También para ejemplos prácticos de todo esto, consulte el enlace que mencioné anteriormente, que muestra ejemplos de todos estos métodos diferentes.
Tenga en cuenta que si llama a una actualización en un objeto separado, siempre habrá una actualización realizada en la base de datos, ya sea que haya cambiado el objeto o no. Si no es lo que desea, debe usar Session.lock () con LockMode.None.
Deberías llamar a actualizar solo si el objeto se cambió fuera del alcance de tu sesión actual (cuando está en modo separado).
As I explained in this article, you should prefer the JPA methods most of the time, and the update
for batch processing tasks.
A JPA or Hibernate entity can be in one of the following four states:
- Transient (New)
- Managed (Persistent)
- Detached
- Removed (Deleted)
The transition from one state to the other is done via the EntityManager or Session methods.
For instance, the JPA EntityManager
provides the following entity state transition methods.
The Hibernate Session
implements all the JPA EntityManager
methods and provides some additional entity state transition methods like save
, saveOrUpdate
and update
.
Persist
To change the state of an entity from Transient (New) to Managed (Persisted), we can use the persist
method offered by the JPA EntityManager
which is also inherited by the Hibernate Session
.
The
persist
method triggers aPersistEvent
which is handled by theDefaultPersistEventListener
Hibernate event listener.
Therefore, when executing the following test case:
doInJPA(entityManager -> {
Book book = new Book()
.setIsbn("978-9730228236")
.setTitle("High-Performance Java Persistence")
.setAuthor("Vlad Mihalcea");
entityManager.persist(book);
LOGGER.info(
"Persisting the Book entity with the id: {}",
book.getId()
);
});
Hibernate generates the following SQL statements:
CALL NEXT VALUE FOR hibernate_sequence
-- Persisting the Book entity with the id: 1
INSERT INTO book (
author,
isbn,
title,
id
)
VALUES (
'Vlad Mihalcea',
'978-9730228236',
'High-Performance Java Persistence',
1
)
Notice that the id
is assigned prior to attaching the Book
entity to the current Persistence Context. This is needed because the managed entities are stored in a Map
structure where the key is formed by the entity type and its identifier and the value is the entity reference. This is the reason why the JPA EntityManager
and the Hibernate Session
are known as the First-Level Cache.
When calling persist
, the entity is only attached to the currently running Persistence Context, and the INSERT can be postponed until the flush
is called.
The only exception is the IDENTITY generator which triggers the INSERT right away since that's the only way it can get the entity identifier. For this reason, Hibernate cannot batch inserts for entities using the IDENTITY generator. For more details about this topic, check out this article.
Save
The Hibernate-specific save
method predates JPA and it's been available since the beginning of the Hibernate project.
The
save
method triggers aSaveOrUpdateEvent
which is handled by theDefaultSaveOrUpdateEventListener
Hibernate event listener. Therefore, thesave
method is equivalent to theupdate
andsaveOrUpdate
methods.
To see how the save
method works, consider the following test case:
doInJPA(entityManager -> {
Book book = new Book()
.setIsbn("978-9730228236")
.setTitle("High-Performance Java Persistence")
.setAuthor("Vlad Mihalcea");
Session session = entityManager.unwrap(Session.class);
Long id = (Long) session.save(book);
LOGGER.info(
"Saving the Book entity with the id: {}",
id
);
});
When running the test case above, Hibernate generates the following SQL statements:
CALL NEXT VALUE FOR hibernate_sequence
-- Saving the Book entity with the id: 1
INSERT INTO book (
author,
isbn,
title,
id
)
VALUES (
'Vlad Mihalcea',
'978-9730228236',
'High-Performance Java Persistence',
1
)
As you can see, the outcome is identical to the persist
method call. However, unlike persist
, the save
method returns the entity identifier.
For more details, check out this article.
Update
The Hibernate-specific update
method is meant to bypass the dirty checking mechanism and force an entity update at the flush time.
The
update
method triggers aSaveOrUpdateEvent
which is handled by theDefaultSaveOrUpdateEventListener
Hibernate event listener. Therefore, theupdate
method is equivalent to thesave
andsaveOrUpdate
methods.
To see how the update
method works consider the following example which persists a Book
entity in one transaction, then it modifies it while the entity is in the detached state, and it forces the SQL UPDATE using the update
method call.
Book _book = doInJPA(entityManager -> {
Book book = new Book()
.setIsbn("978-9730228236")
.setTitle("High-Performance Java Persistence")
.setAuthor("Vlad Mihalcea");
entityManager.persist(book);
return book;
});
LOGGER.info("Modifying the Book entity");
_book.setTitle(
"High-Performance Java Persistence, 2nd edition"
);
doInJPA(entityManager -> {
Session session = entityManager.unwrap(Session.class);
session.update(_book);
LOGGER.info("Updating the Book entity");
});
When executing the test case above, Hibernate generates the following SQL statements:
CALL NEXT VALUE FOR hibernate_sequence
INSERT INTO book (
author,
isbn,
title,
id
)
VALUES (
'Vlad Mihalcea',
'978-9730228236',
'High-Performance Java Persistence',
1
)
-- Modifying the Book entity
-- Updating the Book entity
UPDATE
book
SET
author = 'Vlad Mihalcea',
isbn = '978-9730228236',
title = 'High-Performance Java Persistence, 2nd edition'
WHERE
id = 1
Notice that the UPDATE
is executed during the Persistence Context flush, right before commit, and that's why the Updating the Book entity
message is logged first.
Using @SelectBeforeUpdate
to avoid unnecessary updates
Now, the UPDATE is always going to be executed even if the entity was not changed while in the detached state. To prevent this, you can use the @SelectBeforeUpdate
Hibernate annotation which will trigger a SELECT
statement that fetched loaded state
which is then used by the dirty checking mechanism.
So, if we annotate the Book
entity with the @SelectBeforeUpdate
annotation:
@Entity(name = "Book")
@Table(name = "book")
@SelectBeforeUpdate
public class Book {
//Code omitted for brevity
}
And execute the following test case:
Book _book = doInJPA(entityManager -> {
Book book = new Book()
.setIsbn("978-9730228236")
.setTitle("High-Performance Java Persistence")
.setAuthor("Vlad Mihalcea");
entityManager.persist(book);
return book;
});
doInJPA(entityManager -> {
Session session = entityManager.unwrap(Session.class);
session.update(_book);
});
Hibernate executes the following SQL statements:
INSERT INTO book (
author,
isbn,
title,
id
)
VALUES (
'Vlad Mihalcea',
'978-9730228236',
'High-Performance Java Persistence',
1
)
SELECT
b.id,
b.author AS author2_0_,
b.isbn AS isbn3_0_,
b.title AS title4_0_
FROM
book b
WHERE
b.id = 1
Notice that, this time, there is no UPDATE
executed since the Hibernate dirty checking mechanism has detected that the entity was not modified.
SaveOrUpdate
The Hibernate-specific saveOrUpdate
method is just an alias for save
and update
.
The
saveOrUpdate
method triggers aSaveOrUpdateEvent
which is handled by theDefaultSaveOrUpdateEventListener
Hibernate event listener. Therefore, theupdate
method is equivalent to thesave
andsaveOrUpdate
methods.
Now, you can use saveOrUpdate
when you want to persist an entity or to force an UPDATE
as illustrated by the following example.
Book _book = doInJPA(entityManager -> {
Book book = new Book()
.setIsbn("978-9730228236")
.setTitle("High-Performance Java Persistence")
.setAuthor("Vlad Mihalcea");
Session session = entityManager.unwrap(Session.class);
session.saveOrUpdate(book);
return book;
});
_book.setTitle("High-Performance Java Persistence, 2nd edition");
doInJPA(entityManager -> {
Session session = entityManager.unwrap(Session.class);
session.saveOrUpdate(_book);
});
Beware of the NonUniqueObjectException
One problem that can occur with save
, update
, and saveOrUpdate
is if the Persistence Context already contains an entity reference with the same id and of the same type as in the following example:
Book _book = doInJPA(entityManager -> {
Book book = new Book()
.setIsbn("978-9730228236")
.setTitle("High-Performance Java Persistence")
.setAuthor("Vlad Mihalcea");
Session session = entityManager.unwrap(Session.class);
session.saveOrUpdate(book);
return book;
});
_book.setTitle(
"High-Performance Java Persistence, 2nd edition"
);
try {
doInJPA(entityManager -> {
Book book = entityManager.find(
Book.class,
_book.getId()
);
Session session = entityManager.unwrap(Session.class);
session.saveOrUpdate(_book);
});
} catch (NonUniqueObjectException e) {
LOGGER.error(
"The Persistence Context cannot hold " +
"two representations of the same entity",
e
);
}
Now, when executing the test case above, Hibernate is going to throw a NonUniqueObjectException
because the second EntityManager
already contains a Book
entity with the same identifier as the one we pass to update
, and the Persistence Context cannot hold two representations of the same entity.
org.hibernate.NonUniqueObjectException:
A different object with the same identifier value was already associated with the session : [com.vladmihalcea.book.hpjp.hibernate.pc.Book#1]
at org.hibernate.engine.internal.StatefulPersistenceContext.checkUniqueness(StatefulPersistenceContext.java:651)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performUpdate(DefaultSaveOrUpdateEventListener.java:284)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsDetached(DefaultSaveOrUpdateEventListener.java:227)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:92)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:73)
at org.hibernate.internal.SessionImpl.fireSaveOrUpdate(SessionImpl.java:682)
at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:674)
Merge
To avoid the NonUniqueObjectException
, you need to use the merge
method offered by the JPA EntityManager
and inherited by the Hibernate Session
as well.
As explained in this article, the merge
fetches a new entity snapshot from the database if there is no entity reference found in the Persistence Context, and it copies the state of the detached entity passed to the merge
method.
The
merge
method triggers aMergeEvent
which is handled by theDefaultMergeEventListener
Hibernate event listener.
To see how the merge
method works consider the following example which persists a Book
entity in one transaction, then it modifies it while the entity is in the detached state, and pass the detached entity to merge
in a subsequence Persistence Context.
Book _book = doInJPA(entityManager -> {
Book book = new Book()
.setIsbn("978-9730228236")
.setTitle("High-Performance Java Persistence")
.setAuthor("Vlad Mihalcea");
entityManager.persist(book);
return book;
});
LOGGER.info("Modifying the Book entity");
_book.setTitle(
"High-Performance Java Persistence, 2nd edition"
);
doInJPA(entityManager -> {
Book book = entityManager.merge(_book);
LOGGER.info("Merging the Book entity");
assertFalse(book == _book);
});
When running the test case above, Hibernate executed the following SQL statements:
INSERT INTO book (
author,
isbn,
title,
id
)
VALUES (
'Vlad Mihalcea',
'978-9730228236',
'High-Performance Java Persistence',
1
)
-- Modifying the Book entity
SELECT
b.id,
b.author AS author2_0_,
b.isbn AS isbn3_0_,
b.title AS title4_0_
FROM
book b
WHERE
b.id = 1
-- Merging the Book entity
UPDATE
book
SET
author = 'Vlad Mihalcea',
isbn = '978-9730228236',
title = 'High-Performance Java Persistence, 2nd edition'
WHERE
id = 1
Notice that the entity reference returned by merge
is different than the detached one we passed to the merge
method.
Now, although you should prefer using JPA merge
when copying the detached entity state, the extra SELECT
can be problematic when executing a batch processing task.
For this reason, you should prefer using update
when you are sure that there is no entity reference already attached to the currently running Persistence Context and that the detached entity has been modified.
For more details about this topic, check out this article.
Conclusion
To persist an entity, you should use the JPA persist
method. To copy the detached entity state, merge
should be preferred. The update
method is useful for batch processing tasks only. The save
and saveOrUpdate
are just aliases to update
and you should not probably use them at all.
Some developers call save
even when the entity is already managed, but this is a mistake and triggers a redundant event since, for managed entities, the UPDATE is automatically handled at the Persistence context flush time.
For more details, check out this article.
None of the following answers are right. All these methods just seem to be alike, but in practice do absolutely different things. It is hard to give short comments. Better to give a link to full documentation about these methods: http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/objectstate.html
None of the answers above are complete. Although Leo Theobald answer looks nearest answer.
The basic point is how hibernate is dealing with states of entities and how it handles them when there is a state change. Everything must be seen with respect to flushes and commits as well, which everyone seems to have ignored completely.
NEVER USE THE SAVE METHOD of HIBERNATE. FORGET THAT IT EVEN EXISTS IN HIBERNATE!
Persist
As everyone explained, Persist basically transitions an entity from "Transient" state to "Managed" State. At this point, a slush or a commit can create an insert statement. But the entity will still remains in "Managed" state. That doesn't change with flush.
At this point, if you "Persist" again there will be no change. And there wont be any more saves if we try to persist a persisted entity.
The fun begins when we try to evict the entity.
An evict is a special function of Hibernate which will transition the entity from "Managed" to "Detached". We cannot call a persist on a detached entity. If we do that, then Hibernate raises an exception and entire transaction gets rolled back on commit.
Merge vs Update
These are 2 interesting functions doing different stuff when dealt in different ways. Both of them are trying to transition the entity from "Detached" state to "Managed" state. But doing it differently.
Understand a fact that Detached means kind of an "offline" state. and managed means "Online" state.
Observe the code below:
Session ses1 = sessionFactory.openSession();
Transaction tx1 = ses1.beginTransaction();
HibEntity entity = getHibEntity();
ses1.persist(entity);
ses1.evict(entity);
ses1.merge(entity);
ses1.delete(entity);
tx1.commit();
When you do this? What do you think will happen? If you said this will raise exception, then you are correct. This will raise exception because, merge has worked on entity object, which is detached state. But it doesn't alter the state of object.
Behind the scene, merge will raise a select query and basically returns a copy of entity which is in attached state. Observe the code below:
Session ses1 = sessionFactory.openSession();
Transaction tx1 = ses1.beginTransaction();
HibEntity entity = getHibEntity();
ses1.persist(entity);
ses1.evict(entity);
HibEntity copied = (HibEntity)ses1.merge(entity);
ses1.delete(copied);
tx1.commit();
The above sample works because merge has brought a new entity into the context which is in persisted state.
When applied with Update the same works fine because update doesn't actually bring a copy of entity like merge.
Session ses1 = sessionFactory.openSession();
Transaction tx1 = ses1.beginTransaction();
HibEntity entity = getHibEntity();
ses1.persist(entity);
ses1.evict(entity);
ses1.update(entity);
ses1.delete(entity);
tx1.commit();
At the same time in debug trace we can see that Update hasn't raised SQL query of select like merge.
delete
In the above example I used delete without talking about delete. Delete will basically transition the entity from managed state to "removed" state. And when flushed or commited will issue a delete command to store.
However it is possible to bring the entity back to "managed" state from "removed" state using the persist method.
Hope the above explanation clarified any doubts.