Question 14 · Section 16

What is the Difference Between persist() and merge()

persist() and merge() are two key EntityManager methods for managing entity lifecycles. Understanding the difference between them is critical for proper Hibernate usage.

Language versions: English Russian Ukrainian

Overview

persist() and merge() are two key EntityManager methods for managing entity lifecycles. Understanding the difference between them is critical for proper Hibernate usage.


Junior Level

Main Difference

persist() - for new entities (performs INSERT).

merge() - for updating detached entities (performs UPDATE or INSERT).

// persist - for new entities
User newUser = new User();
newUser.setName("John");
entityManager.persist(newUser);  // INSERT
// newUser is now Persistent

// merge - for detached entities
User detached = getDetachedUser();  // obtained detached somewhere
User managed = entityManager.merge(detached);  // UPDATE
// managed - new managed copy
// detached remains detached!

Behavior

  persist() merge()
For Transient Detached
SQL INSERT UPDATE or INSERT
Returns void Managed entity
Source object Becomes managed Remains detached

persist() Example

User user = new User();
user.setName("John");

entityManager.persist(user);
// user became Persistent
// Can continue working with user
user.setName("Jane");  // dirty checking will trigger

merge() Example

User detached = getDetachedUser();
detached.setName("Changed");

User managed = entityManager.merge(detached);
// detached - still detached!
// managed - new managed copy

detached.setName("NotSaved");    // will NOT affect DB
managed.setName("WillBeSaved");  // will affect (dirty checking)

Middle Level

When merge() is Actually Needed

merge() is typically needed in web applications: an object came from the frontend (JSON -> DTO -> entity), it’s detached - merge copies its state into the managed context.

persist() in Detail

User user = new User();
entityManager.persist(user);

// What happens:
// 1. Checks that entity is not managed
// 2. Generates ID (if auto)
// 3. Adds to persistence context
// 4. Schedules INSERT on flush
// 5. user becomes Persistent

// After persist, can work with it
user.setName("Updated");  // dirty checking

merge() in Detail

User detached = getDetachedUser();
User managed = entityManager.merge(detached);

// What happens inside:
// 1. Checks if entity with same ID exists in persistence context
// 2. If not - loads from DB (SELECT)
// 3. Copies state from detached to managed
// 4. Schedules UPDATE on flush (if changes exist)
// 5. Returns managed entity

// IMPORTANT:
// detached remains detached!
// All further operations - with managed!

persist vs merge - When to Use What

persist() - Transient -> Persistent, INSERT
merge()   - Detached -> Persistent, UPDATE or INSERT

Common Mistakes

// merge() for new entity - unnecessary SELECT
User newUser = new User();
entityManager.merge(newUser);
// First SELECT (existence check), then INSERT

// persist() for new
entityManager.persist(newUser);  // Immediate INSERT

// persist() for detached entity with set ID - EntityExistsException. If ID is generated at DB level, behavior depends on generation strategy.
User detached = getDetachedUser();
entityManager.persist(detached);  // EntityExistsException

// merge() for detached
entityManager.merge(detached);

// Ignoring merge() return value
entityManager.merge(detached);  // result lost!
detached.setName("Changed");    // NOT saved!

// Use return value
User managed = entityManager.merge(detached);
managed.setName("Changed");  // will be saved

Generic save Method

public <T extends BaseEntity> T save(T entity) {
    if (entity.getId() == null) {
        entityManager.persist(entity);
        return entity;
    } else {
        return entityManager.merge(entity);
    }
}

Senior Level

Internal Implementation

persist():
1. check if entity already managed -> error if yes
2. check entity state (not detached)
3. schedule INSERT (doesn't execute immediately!)
4. add to persistence context
5. entity becomes managed

merge():
1. check if entity with same ID in persistence context
   -> yes: use existing managed entity
   -> no: SELECT from DB
2. if not in DB: create new managed instance
3. copy state from detached to managed
4. schedule UPDATE if state changed
5. return managed entity

Key difference:
- persist: original entity becomes managed
- merge: returns NEW managed instance, original stays detached

Performance

persist():
- 0 SELECT queries
- 1 INSERT on flush

merge():
- 1 SELECT (existence check)
- 1 UPDATE or INSERT on flush
- + state copying

For new entities, persist() is faster by 1 SELECT!

Advanced Scenarios

// Scenario: update with version check
@Version
private Integer version;

User detached = getDetachedUser();
User managed = entityManager.merge(detached);
// On flush: UPDATE WHERE id = ? AND version = ?
// If version doesn't match -> OptimisticLockException

Best Practices

persist() for new entities
merge() for detached entities
Check ID before choosing method
Use merge() return value
Understand that merge returns a copy
Generic save() with ID check

merge() for new (unnecessary SELECT)
persist() for detached (error)
Ignoring merge() return value
merge() for persistent (unnecessary SELECT)

Interview Cheat Sheet

Must know:

  • persist() - for new entities (Transient -> Persistent), performs INSERT
  • merge() - for detached entities, returns a NEW managed object, performs UPDATE/INSERT
  • persist() is faster by 1 SELECT (doesn’t check existence)
  • merge() does SELECT before UPDATE/INSERT - checks if entity exists in DB
  • Original after merge() remains detached - all operations with returned object
  • Generic save(): check ID == null -> persist, otherwise merge

Frequent follow-up questions:

  • Why does merge() do SELECT? To check if entity exists and load current state for dirty checking
  • What if persist() is called for detached? EntityExistsException - Hibernate thinks entity is already managed
  • Why does merge() return a new object? Original detached may be from another session, Hibernate creates managed copy in current session
  • When does merge() do INSERT? When entity with that ID doesn’t exist in DB

Red flags (DO NOT say):

  • “merge() for new entities” - unnecessary SELECT
  • “I ignore merge() return value” - changes won’t be saved
  • “persist() for detached” - EntityExistsException
  • “merge() for persistent” - unnecessary SELECT, pointless

Related topics:

  • [[7. Describe the Entity Lifecycle in Hibernate]]
  • [[8. What Are the Transient, Persistent, Detached, Removed States]]
  • [[12. What is Dirty Checking in Hibernate]]
  • [[13. How Does the Flush Mechanism Work in Hibernate]]
  • [[15. What Does the refresh() Method Do]]