What is the difference between persist() and merge() in JPA and Hibernate?
JavaHibernateJpaOrmEntityJava 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)