Coding Streams

How to Fix Hibernate LazyInitializationException in Spring Boot

Akshay Singh
Akshay Singh
4 min readSpring Boot
Fix LazyInitializationException in Spring Boot featured banner

If you are working with Spring Boot and JPA/Hibernate, chances are you have run into the infamous LazyInitializationException. It usually looks something like this:

org.hibernate.LazyInitializationException: could not initialize proxy [com.example.Entity.collection] - no Session

It is one of the most common exceptions in the Spring ecosystem, but it can be incredibly frustrating if you don’t know why it’s happening.

In this post, we will break down exactly why Hibernate throws this exception and walk through 3 clean, production-ready patterns to fix it permanently.


Why Does LazyInitializationException Occur?

To understand the fix, we first need to understand Hibernate's Lazy Loading strategy.

By default, to optimize performance, Hibernate doesn’t load related entities or collections from the database until you explicitly ask for them. For example, if a User entity has a @OneToMany list of Order entities, Hibernate fetches the User but leaves a "proxy" (a placeholder) for the Orders.

The exception happens when you try to access that proxy after the database transaction (and the Hibernate Session) has already closed.

The Lifecycles of a Request

  1. Transaction Starts: A controller calls a service method marked with @Transactional. Hibernate opens a Session.
  2. Data Fetched: The service fetches the User entity. The orders collection is left as a proxy.
  3. Transaction Ends: The service method finishes. The transaction commits, and Hibernate closes the Session.
  4. The Crash: Your controller or a mapping library (like Jackson or MapStruct) tries to read user.getOrders(). Because the Session is dead, Hibernate cannot fetch the data, and boomLazyInitializationException.

⚠️ A Quick Warning about OSIV: Spring Boot enables open-in-view (OSIV) by default, which keeps the Hibernate Session open during the entire web request. While this "hides" the exception during local development, it is a major anti-pattern in production that causes connection pool exhaustion and massive N+1N+1 query performance issues. Turn it off in your application.properties with: spring.jpa.open-in-view=false.


3 Production-Ready Solutions

Now that we know the cause, let's look at the best ways to solve it without sacrificing performance.

1. Use JPQL JOIN FETCH (The Explicit Approach)

If you know a specific business use case requires the parent entity and its child collections, you can instruct Hibernate to fetch them together in a single database query using JOIN FETCH.

public interface UserRepository extends JpaRepository<User, Long> {
 
    @Query("SELECT u FROM User u JOIN FETCH u.orders WHERE u.id = :id")
    Optional<User> findUserWithOrdersById(@Param("id") Long id);
}
 
  • Pros: Highly predictable; results in exactly one highly optimized SQL query.
  • Cons: You have to write custom JPQL queries for different fetch requirements.

2. Use Spring Data @EntityGraph (The Declarative Approach)

If you prefer to avoid writing manual JPQL queries, Spring Data JPA provides the @EntityGraph annotation. This allows you to dynamically specify which attributes or collections should be eagerly loaded for a specific repository method.

public interface UserRepository extends JpaRepository<User, Long> {
 
    @EntityGraph(attributePaths = {"orders"})
    Optional<User> findWithOrdersById(Long id);
}
 

When you call findWithOrdersById, Hibernate automatically generates the required SQL LEFT OUTER JOIN to bring back both the User and their Orders in one go.

  • Pros: Clean, type-safe, and requires zero manual SQL/JPQL.
  • Cons: Can become cluttered if an entity has many complex nested relationships.

3. Use DTO Projection (The Clean Architectural Approach)

The cleanest way to avoid LazyInitializationException altogether is to stop exposing database entities directly to your web or API layers. Instead, project your query results directly into a Data Transfer Object (DTO) inside the transaction.

By using Spring Data Projections or a custom JPQL constructor expression, you fetch only the data you need:

// The DTO Record
public record UserOrdersDto(Long id, String username, List<OrderDto> orders) {}
 
// The Repository
public interface UserRepository extends JpaRepository<User, Long> {
    
    @Query("SELECT new com.example.dto.UserOrdersDto(u.id, u.username, o) " +
           "FROM User u JOIN u.orders o WHERE u.id = :id")
    Optional<UserOrdersDto> findDtoById(@Param("id") Long id);
}
 
  • Pros: Absolute best performance; completely decouples your database schema from your API contract; zero risk of lazy loading issues.
  • Cons: Requires creating extra DTO classes and mapping logic.

Summary: Which Solution Should You Choose?

Scenario Best Solution Why?
Simple queries needing collections @EntityGraph Fast to implement, no custom query strings.
Complex queries with multiple joins JOIN FETCH Gives you granular control over the generated SQL.
Read-only API endpoints / REST APIs DTO Projection Maximizes performance and isolates your entity lifecycle from the view layer.

By explicitly defining your data requirements within the boundaries of your transactions, you will completely eliminate LazyInitializationException while building a faster, more resilient Spring Boot application.

Frequently Asked Questions

Why does LazyInitializationException occur in Hibernate?
This exception occurs when you try to access a lazy-loaded relationship outside of an active database transaction. Once the Session is closed, Hibernate can no longer fetch data dynamically.
Is Open Session in View (OSIV) a good way to fix this exception?
No, OSIV keeps the database connection open until the view is rendered, which leads to resource exhaustion and N+1 query problems in production. It is recommended to disable OSIV.
What is the difference between JOIN FETCH and EntityGraph?
JOIN FETCH is a JPQL keyword that tells Hibernate to fetch the related entity in the same query using a JOIN, while EntityGraph is a Spring Data JPA annotation that allows you to specify which attributes to fetch eagerly without writing custom JPQL queries.
Share

Was this article helpful?

Help us improve by sharing your quick feedback.

Related Posts