Question 7 · Section 16

Describe the Entity Lifecycle in Hibernate

Every entity in Hibernate goes through certain states (lifecycle) during interaction with the database. Understanding the lifecycle is critical for proper Hibernate usage and pr...

Language versions: English Russian Ukrainian

Overview

Every entity in Hibernate goes through certain states (lifecycle) during interaction with the database. Understanding the lifecycle is critical for proper Hibernate usage and preventing errors.

Why this matters: to know which method to call (persist or merge), why changes are saved automatically (dirty checking), why “detached entity passed to persist” occurs.


Junior Level

4 Entity States

An entity in Hibernate can be in one of four states:

  1. Transient (New / Temporary) - created via new, not yet in DB
  2. Persistent (Managed) - saved to DB, tracked by Hibernate
  3. Detached (Disconnected) - was in DB, but session is closed
  4. Removed (Deleted) - marked for deletion, will be deleted on flush
new User() --persist()--> Managed --close()--> Detached
                             |
                          remove()
                             v
                          Removed

Example

// 1. Transient - new object, not in DB
User user = new User();
user.setName("John");

// 2. Persistent - saved, tracked
entityManager.persist(user);
// Now user is in DB and managed by Hibernate

// 3. Detached - session closed
entityManager.close();
// user still exists in memory, but Hibernate no longer tracks

// 4. Removed - marked for deletion
entityManager.remove(user);
// On flush/commit, DELETE will be executed

Middle Level

persist() vs merge()

Operation Transient Detached Persistent
persist() INSERT ERROR ERROR
merge() SELECT+INSERT SELECT+UPDATE SELECT (useless)

State Transitions

Transient -> Persistent:  persist(), merge()
Persistent -> Detached:   close(), clear(), detach()/evict()
Detached -> Persistent:   merge(), update()
Persistent -> Removed:    remove()
Transient -> Detached:    (not possible directly)

Detailed Operation Description

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

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

// remove() - for deletion (DELETE)
entityManager.remove(managedUser);
// On flush, DELETE will be executed

// refresh() - reload from DB
entityManager.refresh(user);
// Updates data from DB, overwriting in-memory changes

// detach()/evict() - detach. evict() - Hibernate-specific (Session). detach() - JPA standard (EntityManager). Use detach() for portability.
entityManager.detach(user);
// user becomes Detached

// clear() - detach all
entityManager.clear();
// All entities become Detached

Dirty Checking

Dirty checking - Hibernate automatically tracks object changes. You just change a field - Hibernate does the UPDATE itself.

@Transactional
public void updateUser(Long id, String name) {
    User user = entityManager.find(User.class, id);  // Persistent
    user.setName(name);
    // NO em.merge() or em.save() needed!
    // Hibernate will automatically detect the change and do UPDATE
}

Common Mistakes

// Detached entity passed to persist
User user = new User();
user.setId(1L);  // ID already set
entityManager.persist(user);  // EntityExistsException or error

// Correct: merge() for detached
User merged = entityManager.merge(user);

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

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

// merge() for persistent (useless)
User user = entityManager.find(User.class, 1L);  // already persistent
User merged = entityManager.merge(user);  // Unnecessary SELECT

Senior Level

Internal Implementation

Persistence Context - container for all managed entities within an EntityManager. EntityEntry - a record within the Persistence Context, stores current state and snapshot. Snapshot - copy of the object state at load time, used for dirty checking.

Persistence Context (StatefulPersistenceContext):

EntityManagerImpl {
    persistenceContext: StatefulPersistenceContext {
        entitiesByKey: Map<EntityKey, Object>,     // cache by ID
        entityEntries: Map<Object, EntityEntry>,   // state tracking
    }
}

EntityEntry stores:
- snapshot - state at load (for dirty checking)
- status - current state (MANAGED, DELETED, etc.)
- loadedState - state when loaded from DB

Dirty Checking Mechanism

1. On load: Hibernate saves entity snapshot
2. On change: field in object is modified
3. On flush: Hibernate compares snapshot with current state
4. If different -> generates UPDATE SQL
5. Updates snapshot

Algorithm:
- O(N) where N = number of entities in persistence context
- Can be slow for large contexts
- Solution: entityManager.clear() periodically

Memory Management for Large Operations

@Transactional
public void batchProcess(List<User> users) {
    for (int i = 0; i < users.size(); i++) {
        entityManager.merge(users.get(i));

        // Periodic persistence context cleanup
        if (i % 50 == 0) {
            entityManager.flush();    // flush to DB
            entityManager.clear();    // clear cache
        }
    }
}

After clear(), all previously loaded/created objects become detached. If the loop continues - subsequent iterations work with new objects, old ones are lost (and accessing them would require merge()).

Best Practices

persist() for new entities
merge() for detached entities
remove() for deletion
Dirty checking for updates (no merge needed)
entityManager.clear() for batch operations
flush + clear every 50-100 entities

persist() for detached (error)
merge() for new (unnecessary SELECT)
merge() for persistent (unnecessary SELECT)
Ignoring entity states
Loading large number of entities without clear

Interview Cheat Sheet

Must know:

  • 4 states: Transient (new), Persistent (managed), Detached (in DB but not tracked), Removed (marked for deletion)
  • persist() - for new (INSERT), merge() - for detached (UPDATE/INSERT)
  • Dirty checking: Hibernate automatically tracks changes to managed entities
  • Persistence Context - container for all managed entities, stores snapshot for dirty checking
  • merge() returns a NEW managed object, the original remains detached
  • entityManager.clear() clears the persistence context, all entities become detached

Frequent follow-up questions:

  • Why is persist() better for new entities than merge()? persist() = immediate INSERT, merge() = first SELECT (check)
  • What is a snapshot? Copy of state at load time, used for dirty checking at flush
  • How to handle 10k+ entities? persist/merge + flush + clear every 50-100 entities
  • Why does merge() return a new object? Because the original may be detached, Hibernate creates a managed copy

Red flags (DO NOT say):

  • “I use merge() for new entities” - unnecessary SELECT
  • “I ignore merge() return value” - changes won’t be saved
  • “persist() for detached with ID” - EntityExistsException
  • “I don’t clean persistence context during batch” - OutOfMemoryError

Related topics:

  • [[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]]
  • [[14. What is the Difference Between persist() and merge()]]
  • [[9. What is the First-Level Cache in Hibernate]]