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

4

135

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
Corkboard answered 22/12, 2010 at 12:20 Comment(2)
Check #161724Alyose
#1070492Castroprauxel
H
159

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.

Heterochromatin answered 22/12, 2010 at 12:57 Comment(3)
Thanks for the info. I see the semantics of both definitions. But the question is about the differences between them. Perhaps present the list of states and 2 sub-sections for each different behavior of persist vs merge?Pieper
if entity is already managed i.e saved or retrieved from db and then changed but not detached. What should be used persist or mergeTuranian
if we wanted to read pages of docs, we wouldn't be looking at a Stackoverflow answer... -1Elk
P
36

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.

Ppm answered 4/11, 2015 at 12:40 Comment(2)
can you please add a source to your explanation? Thanks.Pieper
@Pieper such explaination, as I remember, I have found in a "Beginning Java EE 7" book.Ppm
H
21

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.

Highpressure answered 19/7, 2016 at 8:35 Comment(7)
if entity is already managed i.e saved or retrieved from db and then changed but not detached. What should be used persist or mergeTuranian
You shouldn't call any method if the entity is managed. Just let Hibernate do the UPDATE automatically.Highpressure
tx. does it mean that at the time of commit or at the time of session getting closed, all managed entities will be saved in to DB automatically.Turanian
Yes, prior to commit, there's an auto-flush, unless you are using a read-only Session or Tx.Highpressure
I understand above + If you're using the assigned generator, using merge instead of persist can cause a redundant SQL statement. Tx. But spring data jpa save is using merge in all other cases except when entites are new ie. even when entities are managed. Why is this so?? Users may call save unknowingly on managed entities too only to trigger a merge(again unknowingly) and there is nothing stopping themTuranian
The Spring Data JpaRepository is broken, that's why. Better use the HibernateRepository instead, as it fixes that save issue.Highpressure
thats very disappointing to know that spring guys would do it in a non-standard way.. and most of projects are using spring data api without realizing the pitfalls.. thanks pointing to HibernateRepo which does the job better.. but seems there's gonna be some learning curve.Turanian
A
2

The most important difference is this:

  • In case of the persist method, if the entity that is to be managed in the persistence context, already exists in the persistence context, the new one is ignored. (Basically, NOTHING happens)

  • But in case of the merge method, the entity that is already managed in the persistence context will be replaced by the new entity (Simply, it gets updated) and a copy of this updated entity will then return back. (So from now on any changes should be made to this returned entity if you want to reflect your changes in the persistence context)

Antilebanon answered 17/4, 2019 at 11:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.