What is the difference between persist() and merge() in JPA and Hibernate?

JavaHibernateJpaOrmEntity

Java Problem Overview


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

Java Solutions


Solution 1 - Java

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.

Solution 2 - Java

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.

Solution 3 - Java

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.

Solution 4 - Java

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)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJimit TankView Question on Stackoverflow
Solution 1 - JavaaxtavtView Answer on Stackoverflow
Solution 2 - JavaKrystianView Answer on Stackoverflow
Solution 3 - JavaVlad MihalceaView Answer on Stackoverflow
Solution 4 - JavaOd ChanView Answer on Stackoverflow