Quali sono le differenze tra i diversi metodi di salvataggio in Hibernate?
-
03-07-2019 - |
Domanda
Hibernate ha una manciata di metodi che, in un modo o nell'altro, prendono l'oggetto e lo inseriscono nel database. Quali sono le differenze tra loro, quando usare quale e perché non esiste un solo metodo intelligente che sappia quando usare cosa?
I metodi che ho identificato finora sono:
-
save ()
-
update ()
-
saveOrUpdate ()
-
saveOrUpdateCopy ()
-
merge ()
-
persistono ()
Soluzione
Ecco la mia comprensione dei metodi. Principalmente si basano sulla API sebbene io utilizzarli tutti in pratica.
saveOrUpdate Le chiamate vengono salvate o aggiornate in base ad alcuni controlli. Per esempio. se non esiste un identificatore, viene chiamato il salvataggio. Altrimenti viene chiamato l'aggiornamento.
Salva Persiste un'entità. Assegnerà un identificatore se non esiste. Se lo fa, sta essenzialmente facendo un aggiornamento. Restituisce l'ID generato dell'entità.
Aggiorna Tenta di persistere nell'entità utilizzando un identificatore esistente. Se non esiste un identificatore, credo che venga generata un'eccezione.
saveOrUpdateCopy Questo è obsoleto e non dovrebbe più essere utilizzato. Invece c'è ...
merge Ora è qui che la mia conoscenza inizia a vacillare. La cosa importante qui è la differenza tra entità transitorie, distaccate e persistenti. Per maggiori informazioni sugli stati degli oggetti, dai un'occhiata qui . Con save & amp; aggiornamento, hai a che fare con oggetti persistenti. Sono collegati a una sessione, quindi Hibernate sa cosa è cambiato. Ma quando hai un oggetto transitorio, non c'è nessuna sessione coinvolta. In questi casi è necessario utilizzare l'unione per gli aggiornamenti e persistere per il salvataggio.
persistere Come accennato in precedenza, questo viene utilizzato su oggetti transitori. Non restituisce l'ID generato.
Altri suggerimenti
╔══════════════╦═══════════════════════════════╦════════════════════════════════╗
║ 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() ║
║ ║ ║ ║
╚══════════════╩═══════════════════════════════╩════════════════════════════════╝
-
Consulta il Hibernate Forum per una spiegazione delle sottili differenze tra persistere e salvare. Sembra che la differenza sia il momento in cui l'istruzione INSERT viene eseguita alla fine. Poiché salva restituisce l'identificatore, l'istruzione INSERT deve essere eseguita immediatamente indipendentemente dallo stato della transazione (che in genere è una cosa negativa). Persistere non eseguirà dichiarazioni al di fuori della transazione attualmente in esecuzione solo per assegnare l'identificatore. Save / Persist funzionano entrambi su istanze transitorie , vale a dire istanze a cui non è stato ancora assegnato un identificatore e come tali non vengono salvate nel DB.
Aggiorna e Unisci funzionano entrambi su istanze distaccate , ovvero istanze che hanno una voce corrispondente nel DB ma che sono attualmente non collegato a (o gestito da) una sessione. La differenza tra loro è ciò che accade all'istanza che viene passata alla funzione. aggiorna tenta di ricollegare l'istanza, ciò significa che potrebbe non esserci altra istanza dell'entità persistente collegata alla Sessione in questo momento, altrimenti viene generata un'eccezione. Unisci , tuttavia, copia solo tutti i valori in un'istanza persistente nella Sessione (che verrà caricata se non è attualmente caricata). L'oggetto di input non è cambiato. Quindi unisci è più generale di aggiorna , ma può utilizzare più risorse.
Questo link spiega in modo corretto:
http://www.stevideter.com/2008/12// 07 / saveOrUpdate-versus-merge-in-hibernate /
Tutti abbiamo quei problemi che incontriamo abbastanza raramente che quando li vediamo di nuovo, sappiamo che abbiamo risolto questo problema, ma non possiamo ricordare come.
NonUniqueObjectException generata quando si utilizza Session.saveOrUpdate () in Hibernate è una delle mie. Aggiungerò nuove funzionalità a un'applicazione complessa. Tutti i test delle mie unità funzionano bene. Quindi, testando l'interfaccia utente, cercando di salvare un oggetto, inizio a ottenere un'eccezione con il messaggio & # 8220; un oggetto diverso con lo stesso valore identificativo era già associato alla sessione. & # 8221; Ecco un esempio di codice da 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();
Per comprendere la causa di questa eccezione, è importante comprendere gli oggetti distaccati e cosa succede quando si chiama saveOrUpdate () (o semplicemente update ()) su un oggetto distaccato.
Quando chiudiamo una singola sessione di ibernazione, gli oggetti persistenti con cui stiamo lavorando vengono staccati. Ciò significa che i dati sono ancora nella memoria dell'applicazione, ma Hibernate non è più responsabile del rilevamento delle modifiche agli oggetti.
Se poi modifichiamo il nostro oggetto distaccato e vogliamo aggiornarlo, dobbiamo ricollegare l'oggetto. Durante quel processo di riattacco, Hibernate verificherà se ci sono altre copie dello stesso oggetto. Se ne trova qualcuno, deve dirci che non sa cosa sia reale & reale # 8221; la copia è più. Forse sono state apportate altre modifiche a quelle altre copie che prevediamo di essere salvate, ma Hibernate non le conosce, perché al momento non le stava gestendo.
Invece di salvare dati potenzialmente errati, Hibernate ci informa del problema tramite NonUniqueObjectException.
Quindi cosa dobbiamo fare? In Hibernate 3, abbiamo merge () (in Hibernate 2, usa saveOrUpdateCopy ()). Questo metodo costringerà Hibernate a copiare eventuali modifiche da altre istanze distaccate sull'istanza che si desidera salvare e quindi unisce tutte le modifiche in memoria prima del salvataggio.
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();
È importante notare che l'unione restituisce un riferimento alla versione appena aggiornata dell'istanza. Non è ricollegare l'elemento alla Sessione. Se provi ad esempio l'uguaglianza (item == item3), troverai che in questo caso restituisce false. Probabilmente vorrai lavorare con item3 da questo punto in avanti.
È anche importante notare che l'API Java Persistence (JPA) non ha un concetto di oggetti staccati e ricollegati e utilizza EntityManager.persist () e EntityManager.merge ().
Ho riscontrato in generale che quando si utilizza Hibernate, saveOrUpdate () è in genere sufficiente per le mie esigenze. Di solito ho solo bisogno di usare l'unione quando ho oggetti che possono avere riferimenti a oggetti dello stesso tipo. Più recentemente, la causa dell'eccezione era nel codice che confermava che il riferimento non era ricorsivo. Stavo caricando lo stesso oggetto nella mia sessione come parte della convalida, causando l'errore.
Dove hai riscontrato questo problema? L'unione ha funzionato per te o hai bisogno di un'altra soluzione? Preferisci usare sempre l'unione o preferisci usarlo solo se necessario per casi specifici
In realtà la differenza tra i metodi hibernate save ()
e persist ()
dipende dalla classe del generatore che stiamo usando.
Se viene assegnata la nostra classe di generatori, non vi è alcuna differenza tra i metodi save ()
e persist (
). Perché il generatore "assegnato" significa che come programmatore dobbiamo fornire il valore della chiave primaria per salvare nel database giusto [Spero che tu conosca questo concetto di generatori]
Nel caso di una classe di generatore diversa da quella assegnata, supponiamo che se il nome della nostra classe di generatore è Incremento significa ibernazione, esso stesso assegnerà il valore dell'ID chiave primaria nel diritto del database [diverso dal generatore assegnato, ibernazione utilizzato solo per occuparsi del valore dell'ID chiave primaria ricordare ], quindi in questo caso se chiamiamo il metodo save ()
o persist ()
, inserirà normalmente il record nel database
Ma ascolta la cosa, il metodo save ()
può restituire quel valore ID chiave primaria che viene generato da ibernazione e possiamo vederlo da
long s = session.save(k);
In questo stesso caso, persist ()
non restituirà mai alcun valore al client.
Ho trovato un buon esempio che mostra le differenze tra tutti i metodi di salvataggio in letargo:
In breve, secondo il link sopra:
save ()
- Possiamo invocare questo metodo al di fuori di una transazione. Se lo utilizziamo senza transazione e abbiamo un collegamento in cascata tra entità, viene salvata solo l'entità primaria a meno che non scarichiamo la sessione.
- Quindi, se ci sono altri oggetti mappati dall'oggetto primario, vengono salvati al momento del commit della transazione o quando scarichiamo la sessione.
persistono ()
- È simile all'utilizzo di save () nelle transazioni, quindi è sicuro e si prende cura di tutti gli oggetti a cascata.
saveOrUpdate ()
-
Può essere usato con o senza la transazione, e proprio come save (), se usato senza la transazione, le entità mappate non verranno salvate in un momento, quindi cancelliamo la sessione.
-
Risultati in query di inserimento o aggiornamento basate sui dati forniti. Se i dati sono presenti nel database, viene eseguita la query di aggiornamento.
update ()
- L'aggiornamento di ibernazione deve essere utilizzato laddove sappiamo che stiamo aggiornando solo le informazioni sull'entità. Questa operazione aggiunge l'oggetto entità al contesto persistente e ulteriori modifiche vengono tracciate e salvate quando viene eseguita la transazione.
- Quindi, anche dopo aver chiamato update, se impostiamo dei valori nell'entità, questi verranno aggiornati al momento del commit della transazione.
merge ()
- L'unione in ibernazione può essere utilizzata per aggiornare i valori esistenti, tuttavia questo metodo crea una copia dall'oggetto entità passato e lo restituisce. L'oggetto restituito fa parte del contesto persistente e viene tracciato per eventuali modifiche, l'oggetto passato non viene tracciato. Questa è la principale differenza con merge () rispetto a tutti gli altri metodi.
Anche per esempi pratici di tutti questi, si prega di fare riferimento al link che ho menzionato sopra, mostra esempi per tutti questi diversi metodi.
Tenere presente che se si chiama un aggiornamento su un oggetto distaccato, nel database verrà sempre eseguito un aggiornamento, indipendentemente dal fatto che sia stato modificato l'oggetto. Se non è quello che vuoi, dovresti usare Session.lock () con LockMode.None.
È necessario chiamare l'aggiornamento solo se l'oggetto è stato modificato al di fuori dell'ambito della sessione corrente (in modalità disconnessa).
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.