JPA Entity Lifecycle Statuses: A Comprehensive Guide

Paul Ravvich
Hibernate At the Gates of Mastery
5 min readAug 17, 2023

The four primary entity statuses are New, Managed, Detached, and Removed, each defining how entities interact with the persistence context. New entities are freshly created and have not yet persisted. Managed entities are tracked by the persistence context, automatically syncing changes with the database. Detached entities are untracked and require re-merging for database synchronization. Removed entities are marked for deletion.

JPA Entity Lifecycle Statuses: A Comprehensive Guide

Hi, this is Paul, and welcome to this article, we explore the life cycle statuses of JPA entities.

When working with Java Persistence API (JPA) and its popular implementations like Hibernate or EclipseLink, it’s essential to understand the different life cycle statuses of JPA entities. Each status has its distinct behavior and determines how an entity interacts with the persistence context. In this article, we will delve deep into these statuses, and their transitions, and provide clear examples for each.

Entity Lifecycle Status Overview

Entities in JPA can exist in one of the following statuses:

  1. New
  2. Managed
  3. Detached
  4. Removed

These statuses have a clear sequence of transitions:

  • An entity starts as New when first created.
  • It becomes Managed when associated with a persistence context, e.g., after being persisted or retrieved from the database.
  • An entity can be Detached from the context, which means it’s no longer tracked for changes.
  • Lastly, an entity can be marked as Removed, indicating it will be deleted from the database.

Now, let’s discuss each status in detail.

1. New

When an entity instance is first created using the new keyword, it's in the "New" state. It's not associated with any persistence context, and any changes made to it won't affect the database unless it's explicitly persisted.

Example:

public User createUser(String name) {
User user = new User();
user.setName(name);
return userRepository.save(user); // Here, we persist the new entity.
}

2. Managed

A “Managed” entity is associated with a persistence context, and any changes made to it will be automatically synchronized with the database upon transaction completion. There’s no need to call any save or update method explicitly.

Example:

public User updateUser(Long id, String newName) {
User user = userRepository.findById(id).orElseThrow(() -> new RuntimeException("User not found"));
user.setName(newName);
// No explicit save() call required here, changes will be auto-saved at the end of the transaction.
return user;
}

3. Detached

Entities can become “Detached” from the persistence context. This means they’re no longer monitored for changes by the EntityManager. Changes made to a detached entity won’t be automatically synchronized with the database. For the changes to be reflected in the database, the entity must be merged back into the persistence context.

Entities can become detached in several ways:

  1. When a transaction completes, all managed entities associated with EntityManager become detached.
  2. When an EntityManager is closed.
  3. When the detach the method is explicitly called on an EntityManager.
  4. When entities are serialized (like in a remote call or when sent to another layer of an application).

Let’s consider the following example:

// Load user within a transaction
@Transactional(readOnly = true)
public User loadUser(Long id) {
return userRepository.findById(id).orElseThrow(() -> new RuntimeException("User not found"));
}

// Save a possibly detached user entity
public void saveEditedUser(User editedUser) {
userRepository.save(editedUser);
}

public void demonstrateDetachedLifecycle(Long userId) {
User user = loadUser(userId); // Here, the user entity is managed within the transaction.

// Once the above method completes, the transaction ends, and the user entity becomes detached.

// Some changes to the user entity can be made here...

saveEditedUser(user); // The entity is reattached and updated in the database.
}

In this demonstrateDetachedLifecycle method, we've illustrated the transition of an entity from a managed state within a transaction to a detached state after the transaction and then back to a managed state when it's saved again.

4. Removed

An entity can be marked as “Removed”, signaling that it will be deleted from the database once the transaction completes. This is the end state of an entity before it gets garbage collected.

Example:

public void deleteUser(Long id) {
User user = userRepository.findById(id).orElseThrow(() -> new RuntimeException("User not found"));
userRepository.delete(user); // Here, the entity is marked for removal and will be deleted from the database at the end of the transaction.
}

Conclusion

When working with JPA and Spring Data, it’s wise to know when to explicitly call methods such as save()and when it's redundant. Improper handling of save operations can lead to issues like unintended data updates, reduced performance, and potential version conflicts.

When to call save() and other methods:

  1. Entities in the “New” state: When you have a new entity (i.e., it has not been saved to the database yet), an explicit call to save() is necessary to persist it.
  2. Detached entities: If you have an entity that was previously fetched but is currently not associated with the active persistence context (i.e., it’s in the “Detached” state), an explicit call to save() or merge() is required to save any modifications.
  3. Deleting an entity: Use the delete() method to remove an entity from the database.

When not to call save():

  1. Entities in the “Managed” state: If an entity is already in a managed state and is associated with the current persistence context, any changes to it will be automatically synchronized with the database upon transaction completion. In such cases, explicitly calling save() is redundant.

Risks of calling save() when it's not required:

  1. Performance: Excessive save() calls can lead to additional system overhead, as each call might initiate a database query.
  2. Unintended updates: Calling save() on an already managed entity can result in unintended updates of all fields of the entity, even if they were not modified.
  3. Version conflicts: If versioning mechanisms are in use (for example, using the @Version annotation), improper save operations can lead to version conflicts.
  4. Unexpected states: Depending on your JPA provider’s settings and the use case, calling save() on an entity might lead to various side effects, such as re-saving associated entities.

When working with JPA and Spring Data, understanding the lifecycle of entities and employing methods like save(), delete(), and others appropriately is crucial. This helps avoid mistakes related to unintended data modifications and ensures the optimal performance of your application.

Paul Ravvich

Thank you for reading until the end. Before you go:

--

--

Paul Ravvich
Hibernate At the Gates of Mastery

Software Engineer with over 10 years of XP. Join me for tips on Programming, System Design, and productivity in tech! New articles every Tuesday and Thursday!