eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (cat=Spring Boot)
announcement - icon

Refactor Java code safely — and automatically — with OpenRewrite.

Refactoring big codebases by hand is slow, risky, and easy to put off. That’s where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.

Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions — one for newcomers and one for experienced users. You’ll see how recipes work, how to apply them across projects, and how to modernize code with confidence.

Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.

Partner – LambdaTest – NPI EA (cat=Testing)
announcement - icon

Regression testing is an important step in the release process, to ensure that new code doesn't break the existing functionality. As the codebase evolves, we want to run these tests frequently to help catch any issues early on.

The best way to ensure these tests run frequently on an automated basis is, of course, to include them in the CI/CD pipeline. This way, the regression tests will execute automatically whenever we commit code to the repository.

In this tutorial, we'll see how to create regression tests using Selenium, and then include them in our pipeline using GitHub Actions:, to be run on the LambdaTest cloud grid:

>> How to Run Selenium Regression Tests With GitHub Actions

Course – LJB – NPI EA (cat = Core Java)
announcement - icon

Code your way through and build up a solid, practical foundation of Java:

>> Learn Java Basics

1. Overview

Every Hibernate entity naturally has a lifecycle within the framework – it’s either in a transient, managed, detached or deleted state.

Understanding these states on both conceptual and technical level is essential to be able to use Hibernate properly.

To learn about various Hibernate methods that deal with entities, have a look at one of our previous tutorials.

2. Helper Methods

Throughout this tutorial, we’ll consistently use several helper methods:

  • HibernateLifecycleUtil.getManagedEntities(session) – we’ll use it to get all managed entities from a Session’s internal store
  • DirtyDataInspector.getDirtyEntities() – we’re going to use this method to get a list of all entities that were marked as ‘dirty’
  • HibernateLifecycleUtil.queryCount(query) – a convenient method to do count(*) query against the embedded database

All of the above helper methods are statically imported for better readability. You can find their implementations in the GitHub project linked at the end of this article.

3. It’s All About Persistence Context

Before getting into the topic of entity lifecycle, first, we need to understand the persistence context.

Simply put, the persistence context sits between client code and data store. It’s a staging area where persistent data is converted to entities, ready to be read and altered by client code.

Theoretically speaking, the persistence context is an implementation of the Unit of Work pattern. It keeps track of all loaded data, tracks changes of that data, and is responsible to eventually synchronize any changes back to the database at the end of the business transaction.

JPA EntityManager and Hibernate’s Session are an implementation of the persistence context concept. Throughout this article, we’ll use Hibernate Session to represent persistence context.

Hibernate entity lifecycle state explains how the entity is related to a persistence context, as we’ll see next.

4. Managed Entity

A managed entity is a representation of a database table row (although that row doesn’t have to exist in the database yet).

This is managed by the currently running Session, and every change made on it will be tracked and propagated to the database automatically.

The Session either loads the entity from the database or re-attaches a detached entity. We’ll discuss detached entities in section 5.

Let’s observe some code to get clarification.

Our sample application defines one entity, the FootballPlayer class. At startup, we’ll initialize the data store with some sample data:

+-------------------+-------+
| Name              |  ID   |
+-------------------+-------+
| Cristiano Ronaldo | 1     |
| Lionel Messi      | 2     |
| Gigi Buffon       | 3     |
+-------------------+-------+

Let’s say we want to change the name of Buffon to start with – we want to put in his full name Gianluigi Buffon instead of Gigi Buffon.

First, we need to start our unit of work by obtaining a Session:

Session session = sessionFactory.openSession();

In a server environment, we may inject a Session to our code via a context-aware proxy. The principle remains the same: we need a Session to encapsulate the business transaction of our unit of work.

Next, we’ll instruct our Session to load the data from the persistent store:

assertThat(getManagedEntities(session)).isEmpty();

List<FootballPlayer> players = s.createQuery("from FootballPlayer").getResultList();

assertThat(getManagedEntities(session)).size().isEqualTo(3);

When we first obtain a Session, its persistent context store is empty, as shown by our first assert statement.

Next, we’re executing a query which retrieves data from the database, creates entity representation of the data, and finally returns the entity for us to use.

Internally, the Session keeps track of all entities it loads in the persistent context store. In our case, the Session’s internal store will contain 3 entities after the query.

Now let’s change Gigi’s name:

Transaction transaction = session.getTransaction();
transaction.begin();

FootballPlayer gigiBuffon = players.stream()
  .filter(p -> p.getId() == 3)
  .findFirst()
  .get();

gigiBuffon.setName("Gianluigi Buffon");
transaction.commit();

assertThat(getDirtyEntities()).size().isEqualTo(1);
assertThat(getDirtyEntities().get(0).getName()).isEqualTo("Gianluigi Buffon");

4.1. How Does It Work?

On call to transaction commit() or flush(), the Session will find any dirty entities from its tracking list and synchronize the state to the database.

Notice that we didn’t need to call any method to notify Session that we changed something in our entity – since it’s a managed entity, all changes are propagated to the database automatically.

A managed entity is always a persistent entity – it must have a database identifier, even though the database row representation is not yet created i.e. the INSERT statement is pending the end of the unit of work.

See the chapter about transient entities below.

5. Detached Entity

detached entity is just an ordinary entity POJO whose identity value corresponds to a database row. The difference from a managed entity is that it’s not tracked anymore by any persistence context.

An entity can become detached when the Session used to load it was closed, or when we call Session.evict(entity) or Session.clear().

Let’s see it in the code:

FootballPlayer cr7 = session.get(FootballPlayer.class, 1L);

assertThat(getManagedEntities(session)).size().isEqualTo(1);
assertThat(getManagedEntities(session).get(0).getId()).isEqualTo(cr7.getId());

session.evict(cr7);

assertThat(getManagedEntities(session)).size().isEqualTo(0);

Our persistence context will not track the changes in detached entities:

cr7.setName("CR7");
transaction.commit();

assertThat(getDirtyEntities()).isEmpty();

Session.merge(entity)/Session.update(entity) can (re)attach a session:

FootballPlayer messi = session.get(FootballPlayer.class, 2L);

session.evict(messi);
messi.setName("Leo Messi");
transaction.commit();

assertThat(getDirtyEntities()).isEmpty();

transaction = startTransaction(session);
session.update(messi);
transaction.commit();

assertThat(getDirtyEntities()).size().isEqualTo(1);
assertThat(getDirtyEntities().get(0).getName()).isEqualTo("Leo Messi");

For reference on both Session.merge() and Session.update() see here.

5.1. The Identity Field Is All That Matters

Let’s have a look at the following logic:

FootballPlayer gigi = new FootballPlayer();
gigi.setId(3);
gigi.setName("Gigi the Legend");
session.update(gigi);

In the example above, we’ve instantiated an entity in the usual way via its constructor. We’ve populated the fields with values and we’ve set the identity to 3, which corresponds to the identity of persistent data that belongs to Gigi Buffon. Calling update() has exactly the same effect as if we’ve loaded the entity from another persistence context.

In fact, Session doesn’t distinguish where a re-attached entity originated from.

It’s quite a common scenario in web applications to construct detached entities from HTML form values.

As far as Session is concerned, a detached entity is just a plain entity whose identity value corresponds to persistent data.

Be aware that the example above just serves a demo purpose. and we need to know exactly what we’re doing. Otherwise, we could end up with null values across our entity if we just set the value on the field we want to update, leaving the rest untouched (so, effectively null).

6. Transient Entity

A transient entity is simply an entity object that has no representation in the persistent store and is not managed by any Session.

A typical example of a transient entity would be instantiating a new entity via its constructor.

To make a transient entity persistent, we need to call Session.save(entity) or Session.saveOrUpdate(entity):

FootballPlayer neymar = new FootballPlayer();
neymar.setName("Neymar");
session.save(neymar);

assertThat(getManagedEntities(session)).size().isEqualTo(1);
assertThat(neymar.getId()).isNotNull();

int count = queryCount("select count(*) from Football_Player where name='Neymar'");

assertThat(count).isEqualTo(0);

transaction.commit();
count = queryCount("select count(*) from Football_Player where name='Neymar'");

assertThat(count).isEqualTo(1);

As soon as we execute Session.save(entity), the entity is assigned an identity value and becomes managed by the Session. However, it might not yet be available in the database as the INSERT operation might be delayed until the end of the unit of work.

7. Deleted Entity

An entity is in a deleted (removed) state if Session.delete(entity) has been called, and the Session has marked the entity for deletion. The DELETE command itself might be issued at the end of the unit of work.

Let’s see it in the following code:

session.delete(neymar);

assertThat(getManagedEntities(session).get(0).getStatus()).isEqualTo(Status.DELETED);

However, notice that the entity stays in the persistent context store until the end of the unit of work.

8. Conclusion

The concept of persistence context is central to understanding the lifecycle of Hibernate entities. We’ve clarified the lifecycle by looking into the code examples demonstrating each status.

The code backing this article is available on GitHub. Once you're logged in as a Baeldung Pro Member, start learning and coding on the project.
Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Course – LS – NPI EA (cat=REST)

announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (tag=Refactoring)
announcement - icon

Modern Java teams move fast — but codebases don’t always keep up. Frameworks change, dependencies drift, and tech debt builds until it starts to drag on delivery. OpenRewrite was built to fix that: an open-source refactoring engine that automates repetitive code changes while keeping developer intent intact.

The monthly training series, led by the creators and maintainers of OpenRewrite at Moderne, walks through real-world migrations and modernization patterns. Whether you’re new to recipes or ready to write your own, you’ll learn practical ways to refactor safely and at scale.

If you’ve ever wished refactoring felt as natural — and as fast — as writing code, this is a good place to start.

eBook Jackson – NPI EA – 3 (cat = Jackson)