What is the difference between persist() and merge() in Hibernate?
persist()
can create a UPDATE & INSERT query, eg:
SessionFactory sef = cfg.buildSessionFactory();
Session session = sef.openSession();
A a=new A();
session.persist(a);
a.setName("Mario");
session.flush();
in this case query will be generated like this:
Hibernate: insert into A (NAME, ID) values (?, ?)
Hibernate: update A set NAME=? where ID=?
so persist()
method can generate an Insert and an Update.
Now with merge()
:
SessionFactory sef = cfg.buildSessionFactory();
Session session = sef.openSession();
Singer singer = new Singer();
singer.setName("Luciano Pavarotti");
session.merge(singer);
session.flush();
This is what I see in the database:
SINGER_ID SINGER_NAME
1 Ricky Martin
2 Madonna
3 Elvis Presley
4 Luciano Pavarotti
Now update a record using merge()
SessionFactory sef = cfg.buildSessionFactory();
Session session = sef.openSession();
Singer singer = new Singer();
singer.setId(2);
singer.setName("Luciano Pavarotti");
session.merge(singer);
session.flush();
This is what I see in the database:
SINGER_ID SINGER_NAME
1 Ricky Martin
2 Luciano Pavarotti
3 Elvis Presley
JPA specification contains a very precise description of semantics of these operations, better than in javadoc:
The semantics of the persist operation, applied to an entity X are as follows: If X is a new entity, it becomes managed. The entity X will be entered into the database at or before transaction commit or as a result of the flush operation. If X is a preexisting managed entity, it is ignored by the persist operation. However, the persist operation is cascaded to entities referenced by X, if the relationships from X to these other entities are annotated with the cascade=PERSIST or cascade=ALL annotation element value or specified with the equivalent XML descriptor element. If X is a removed entity, it becomes managed. If X is a detached object, the EntityExistsException may be thrown when the persist operation is invoked, or the EntityExistsException or another PersistenceException may be thrown at flush or commit time. For all entities Y referenced by a relationship from X, if the relationship to Y has been annotated with the cascade element value cascade=PERSIST or cascade=ALL, the persist operation is applied to Y.
The semantics of the merge operation applied to an entity X are as follows: If X is a detached entity, the state of X is copied onto a pre-existing managed entity instance X' of the same identity or a new managed copy X' of X is created. If X is a new entity instance, a new managed entity instance X' is created and the state of X is copied into the new managed entity instance X'. If X is a removed entity instance, an IllegalArgumentException will be thrown by the merge operation (or the transaction commit will fail). If X is a managed entity, it is ignored by the merge operation, however, the merge operation is cascaded to entities referenced by relationships from X if these relationships have been annotated with the cascade element value cascade=MERGE or cascade=ALL annotation. For all entities Y referenced by relationships from X having the cascade element value cascade=MERGE or cascade=ALL, Y is merged recursively as Y'. For all such Y referenced by X, X' is set to reference Y'. (Note that if X is managed then X is the same object as X'.) If X is an entity merged to X', with a reference to another entity Y, where cascade=MERGE or cascade=ALL is not specified, then navigation of the same association from X' yields a reference to a managed object Y' with the same persistent identity as Y.
This is coming from JPA
. In a very simple way:
persist(entity) should be used with totally new entities, to add them to DB (if entity already exists in DB there will be EntityExistsException throw).
merge(entity) should be used, to put entity back to persistence context if the entity was detached and was changed.
Persist should be called only on new entities, while merge
is meant to reattach detached entities.
If you're using the assigned generator, using merge
instead of persist
can cause a redundant SQL statement.
Also, calling merge for managed entities is also a mistake since managed entities are automatically managed by Hibernate, and their state is synchronized with the database record by the dirty checking mechanism upon flushing the Persistence Context.
The most important difference is this:
In case of persist method, if the entity that is to be managed in the persistence context, already exists in persistence context, the new one is ignored. (NOTHING happened)
But in case of merge method, the entity that is already managed in persistence context will be replaced by the new entity (updated) and a copy of this updated entity will return back. (from now on any changes should be made on this returned entity if you want to reflect your changes in persistence context)
Success story sharing
persist
vsmerge
?