What is the difference between persist() and merge() in JPA and Hibernate?
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
orcascade=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 theEntityExistsException
or
anotherPersistenceException
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
orcascade=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 valuecascade=MERGE
or
cascade=ALL
annotation.For all
entities Y referenced by relationships
from X having the cascade element
valuecascade=MERGE
orcascade=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,
wherecascade=MERGE
orcascade=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.
JPA EntityManager: Why use persist() over merge()?
Either way will add an entity to a PersistenceContext, the difference is in what you do with the entity afterwards.
Persist takes an entity instance, adds it to the context and makes that instance managed (i.e. future updates to the entity will be tracked).
Merge returns the managed instance that the state was merged with. It does return something that exists in PersistenceContext or creates a new instance of your entity. In any case, it will copy the state from the supplied entity, and return a managed copy. The instance you pass in will not be managed (any changes you make will not be part of the transaction - unless you call merge again). Though you can use the returned instance (managed one).
Maybe a code example will help.
MyEntity e = new MyEntity();
// scenario 1
// tran starts
em.persist(e);
e.setSomeField(someValue);
// tran ends, and the row for someField is updated in the database
// scenario 2
// tran starts
e = new MyEntity();
em.merge(e);
e.setSomeField(anotherValue);
// tran ends but the row for someField is not updated in the database
// (you made the changes *after* merging)
// scenario 3
// tran starts
e = new MyEntity();
MyEntity e2 = em.merge(e);
e2.setSomeField(anotherValue);
// tran ends and the row for someField is updated
// (the changes were made to e2, not e)
Scenario 1 and 3 are roughly equivalent, but there are some situations where you'd want to use Scenario 2.
Hibernate merge vs. persist. Were there changes?
Possible Duplicate of Update Vs Merge
Whats happening here is:
Edit Mode :
List<UserRole> roles = entity.getRoles(); //Gets Existing Roles from DB
for(UserRole r : roles) {
Em.get().remove(r); //Removes Roles to existing user
}
roles.clear(); // Clean up local memory
for(RoleEnum r : selectedRoles) { // User Input Roles
UserRole role = new UserRole(entity, r); // New Entity with existing user
Em.get().persist(role); // Role Entity Referenced to existing user object, saved
}
Em.get().merge(entity); // ?? No Need in edit unless roles are stored in user table
Em.get().flush();
New User Mode :
List<UserRole> roles = entity.getRoles(); // New Detached User Entity Roles
for(UserRole r : roles) { // Probably Empty Roles Array
Em.get().remove(r); // Removed roles
}
roles.clear(); // Clean up Memory
for(RoleEnum r : selectedRoles) { // Copy from App Roles
UserRole role = new UserRole(entity, r); //Create new role
Em.get().persist(role); //Save Role to DB
}
Em.get().merge(entity); // Trying to merge non existing Entity <-- This is where error appears
Em.get().flush();
The persist method works because it has decides when to use insert or update command. Since new user entity has no ID set to it, it has no idea what to do with it, while it may have worked in past, actual behavior of mergig is very well explain in this thread merging a detached or new entity with an existing entity in hibernate/jpa best practice question
See for yourself :
If your entity is a detached entity the only thing u really need to do
is to invoke entityManager.merge(user). You dont need to exec any
finder method. If your entity is not detached but rather new (it does
not have id specified) you should find appropriate entity in the
database prior performing any modification operations on that entity
and merge it afterwards.
Another detailed reference is given here : persist() and merge() in JPA and Hibernate
Here is the reference from docs :
Serializable
save(Object object) throws HibernateException
Persist the given transient instance, first assigning a generated identifier. (Or using the current value of the identifier property if the assigned generator is used.) This operation cascades to associated instances if the association is mapped with cascade="save-update".
Parameters:
object - a transient instance of a persistent class
Returns:
the generated identifier
Throws:
HibernateException
persist
void persist(String entityName,
Object object)
throws HibernateException
Make a transient instance persistent. This operation cascades to associated instances if the association is mapped with cascade="persist".
The semantics of this method are defined by JSR-220.
Parameters:
object - a transient instance to be made persistent
Throws:
HibernateException
merge
Object merge(String entityName,
Object object)
throws HibernateException
Copy the state of the given object onto the persistent object with the same identifier. If there is no persistent instance currently associated with the session, it will be loaded. Return the persistent instance. If the given instance is unsaved, save a copy of and return it as a newly persistent instance. The given instance does not become associated with the session. This operation cascades to associated instances if the association is mapped with cascade="merge".
The semantics of this method are defined by JSR-220.
Parameters:
object - a detached instance with state to be copied
Returns:
an updated persistent instance
Throws:
HibernateException
save() and persist() result in an SQL INSERT, delete() in an SQL
DELETE and update() or merge() in an SQL UPDATE. Changes to persistent
instances are detected at flush time and also result in an SQL UPDATE.
saveOrUpdate() and replicate() result in either an INSERT or an
UPDATE.
Conclusion: Functions are behaving as they are intended.
JPA merge vs. persist
It's not a good idea using merge
when a persist
suffices - merge
does quite a lot more of work. The topic has been discussed on StackOverflow before, and this article explains in detail the differences, with some nice flow diagrams to make things clear.
What are the differences between the different saving methods in Hibernate?
Here's my understanding of the methods. Mainly these are based on the API though as I don't use all of these in practice.
saveOrUpdate
Calls either save or update depending on some checks. E.g. if no identifier exists, save is called. Otherwise update is called.
save
Persists an entity. Will assign an identifier if one doesn't exist. If one does, it's essentially doing an update. Returns the generated ID of the entity.
update
Attempts to persist the entity using an existing identifier. If no identifier exists, I believe an exception is thrown.
saveOrUpdateCopy
This is deprecated and should no longer be used. Instead there is...
merge
Now this is where my knowledge starts to falter. The important thing here is the difference between transient, detached and persistent entities. For more info on the object states, take a look here. With save & update, you are dealing with persistent objects. They are linked to a Session so Hibernate knows what has changed. But when you have a transient object, there is no session involved. In these cases you need to use merge for updates and persist for saving.
persist
As mentioned above, this is used on transient objects. It does not return the generated ID.
JPA OneToOne difference between cascade merge and persist
I would not dream to challenge the uber answer of DannyMo, but I wanted to make an addition:
Persist and merge are designed as a way to keep one managed instance of certain object.
If you use persist it means the object does not exist yet, so making it a unique managed instance doesn't hurt.
When you use merge, you take into consideration that a managed instance of the object may already exist. You don't wanna replace that unique managed instance, because some other object might reference it, believing it is the managed object.
If you want to make operations on the object after the merge, the correct merge would look like this:
managedObject = em.merge(object); // or just object = em.merge(object)
//You cannot do it with persist since it returns null
If you tried to check if managedObject
and object
points to the same object instance checking if(managedObject == object)
you will get false (true is possible when you use merge on already managed object and the operation is ignored).
If you use merge on outdated version of object, which you passed as argument to the previous merge, jpa doesn't know how to find the right object since it has yet no id. It is assumed that it is a new object and new managed instance will be created.
I'm quite a rookie. Please correct me if I am wrong anywhere.
Related Topics
Why Is the Catch(Exception) Almost Always a Bad Idea
What Is a Class Literal in Java
Test Class with a New() Call in It with Mockito
Calculate Number of Weekdays Between Two Dates in Java
How to Make Java Print Quotes, Like "Hello"
Hashmap: One Key, Multiple Values
Wrong Ordering in Generated Table in JPA
Uninitialized Variables and Members in Java
Unsupportedoperationexception When Trying to Remove from the List Returned by Array.Aslist
Java 8 Nested (Multi Level) Group By
Drawing a Rectangle That Won't Disappear in Next Paint
Setting the Maximum Size of a Jdialog
Big-O Summary for Java Collections Framework Implementations
Access Restriction: the Type 'Application' Is Not API (Restriction on Required Library Rt.Jar)