Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JPA EntityManager: Why use persist() over merge()?

EntityManager.merge() can insert new objects and update existing ones.

Why would one want to use persist() (which can only create new objects)?

like image 949
Aaron Digulla Avatar asked Jul 01 '09 16:07

Aaron Digulla


People also ask

What is the difference between persist and merge in JPA?

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.

What does EntityManager persist do?

The EntityManager. persist() operation is used to insert a new object into the database. persist does not directly insert the object into the database: it just registers it as new in the persistence context (transaction).

How does merge work in JPA?

JPA's merge method copies the state of a detached entity to a managed instance of the same entity. Hibernate, therefore, executes an SQL SELECT statement to retrieve a managed entity from the database.

What does persist mean in JPA?

"Persist" means "lives on after the application is shut down". The object is not just in volatile memory; it's in more permanent storage on disk. If the application is shut down, or the user ends their session and begins a new one, the old data is still available from permanent storage on disk.


2 Answers

Persist and merge are for two different purposes (they aren't alternatives at all).

(edited to expand differences information)

persist:

  • Insert a new register to the database
  • Attach the object to the entity manager.

merge:

  • Find an attached object with the same id and update it.
  • If exists update and return the already attached object.
  • If doesn't exist insert the new register to the database.

persist() efficiency:

  • It could be more efficient for inserting a new register to a database than merge().
  • It doesn't duplicates the original object.

persist() semantics:

  • It makes sure that you are inserting and not updating by mistake.

Example:

{     AnyEntity newEntity;     AnyEntity nonAttachedEntity;     AnyEntity attachedEntity;      // Create a new entity and persist it             newEntity = new AnyEntity();     em.persist(newEntity);      // Save 1 to the database at next flush     newEntity.setValue(1);      // Create a new entity with the same Id than the persisted one.     AnyEntity nonAttachedEntity = new AnyEntity();     nonAttachedEntity.setId(newEntity.getId());      // Save 2 to the database at next flush instead of 1!!!     nonAttachedEntity.setValue(2);     attachedEntity = em.merge(nonAttachedEntity);      // This condition returns true     // merge has found the already attached object (newEntity) and returns it.     if(attachedEntity==newEntity) {             System.out.print("They are the same object!");     }      // Set 3 to value     attachedEntity.setValue(3);     // Really, now both are the same object. Prints 3     System.out.println(newEntity.getValue());      // Modify the un attached object has no effect to the entity manager     // nor to the other objects     nonAttachedEntity.setValue(42); } 

This way only exists 1 attached object for any register in the entity manager.

merge() for an entity with an id is something like:

AnyEntity myMerge(AnyEntity entityToSave) {     AnyEntity attached = em.find(AnyEntity.class, entityToSave.getId());     if(attached==null) {             attached = new AnyEntity();             em.persist(attached);     }     BeanUtils.copyProperties(attached, entityToSave);      return attached; } 

Although if connected to MySQL merge() could be as efficient as persist() using a call to INSERT with ON DUPLICATE KEY UPDATE option, JPA is a very high level programming and you can't assume this is going to be the case everywhere.

like image 44
Josep Panadero Avatar answered Oct 06 '22 20:10

Josep Panadero


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 (ie future updates to the entity will be tracked).

Merge returns the managed instance that the state was merged to. It does return something what 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 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.

like image 136
Mike Avatar answered Oct 06 '22 21:10

Mike