0
0
SpringbootDebug / FixIntermediate · 4 min read

How to Fix Lazy Initialization Exception in Spring Boot

The LazyInitializationException in Spring Boot happens when you try to access a lazy-loaded entity outside of an active session or transaction. To fix it, ensure the entity is fetched within a transaction or use fetch = FetchType.EAGER or JOIN FETCH queries to load related data eagerly.
🔍

Why This Happens

This exception occurs because Spring uses lazy loading by default for related entities. When you try to access a lazy-loaded property after the database session is closed, Spring cannot fetch the data and throws LazyInitializationException.

java
import jakarta.persistence.*;
import java.util.List;

@Entity
public class User {
    @Id
    private Long id;

    @OneToMany(fetch = FetchType.LAZY)
    private List<Order> orders;

    // getters and setters
}

// In a service method
@Transactional
public User getUser(Long id) {
    User user = entityManager.find(User.class, id);
    return user;
}

// Later in controller or outside transaction
User user = userService.getUser(1L);
List<Order> orders = user.getOrders(); // Throws LazyInitializationException here
Output
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
🔧

The Fix

To fix this, you can fetch the lazy collection inside the transaction or use eager fetching. One common way is to use JOIN FETCH in your query to load related entities eagerly before the session closes.

java
import jakarta.persistence.*;
import java.util.List;

@Entity
public class User {
    @Id
    private Long id;

    @OneToMany(fetch = FetchType.LAZY)
    private List<Order> orders;

    // getters and setters
}

// In repository or DAO
public User findUserWithOrders(Long id) {
    return entityManager.createQuery(
        "SELECT u FROM User u JOIN FETCH u.orders WHERE u.id = :id", User.class)
        .setParameter("id", id)
        .getSingleResult();
}

// In service
@Transactional
public User getUserWithOrders(Long id) {
    return findUserWithOrders(id);
}

// Now accessing orders outside transaction works
User user = userService.getUserWithOrders(1L);
List<Order> orders = user.getOrders(); // No exception, orders loaded eagerly
Output
No exception; orders list is accessible and loaded
🛡️

Prevention

To avoid this error in the future, always access lazy-loaded properties within a transaction or use eager fetching when you know you need related data. Also, consider using DTOs with explicit queries to fetch only needed data. Avoid exposing entities directly to the view layer.

  • Use @Transactional on service methods accessing lazy properties.
  • Use JOIN FETCH queries to load related entities eagerly.
  • Consider FetchType.EAGER only if it won't cause performance issues.
  • Use projections or DTOs to fetch required data explicitly.
⚠️

Related Errors

Other errors related to lazy loading include:

  • org.hibernate.ObjectNotFoundException: Happens when a proxy is accessed but the entity does not exist in the database.
  • org.hibernate.HibernateException: No Session: Occurs when trying to access lazy data without an active Hibernate session.
  • StackOverflowError: Can happen if bidirectional lazy relationships cause infinite loops during serialization.

Quick fixes include ensuring transactions are active, using DTOs, and managing serialization carefully.

Key Takeaways

LazyInitializationException happens when lazy data is accessed outside a transaction.
Fix it by fetching lazy data inside a transaction or using eager fetching with JOIN FETCH.
Use @Transactional on service methods that access lazy-loaded properties.
Avoid exposing entities directly; use DTOs or projections for safer data access.
Be mindful of performance when switching from lazy to eager fetching.