LazyInitializationException

The Most Famous Hibernate Error

A lazy proxy can load its data only while the persistence context (Session) is open, which in Spring means inside the @Transactional method. Touch it after the transaction ends and you get:

Example

public Order getOrder(Long id) {                 // no @Transactional
    return orderRepository.findById(id).orElseThrow();
}
// in the controller:
order.getItems().size();

Example output

org.hibernate.LazyInitializationException: Cannot lazily initialize collection of role 'com.shopease.order.Order.items' with key '501' (no session)

org.hibernate.LazyInitializationException: Could not initialize proxy [com.shopease.catalog.Category#3] - no session

Why It Happens

Controller ──► OrderService.getOrder() ──► repository.findById()
                    │  transaction + Session open
                    │  Order loaded, items = uninitialized collection
                    ▼  transaction ends, Session closed, Order is now DETACHED
 Controller: order.getItems().size()  ──►  no Session to run SELECT  ──►  LazyInitializationException

Correct Fixes

  1. Load what you need inside the transaction with a fetch join or @EntityGraph (next topics).
  2. Map to a DTO inside the service (the transaction is still open), and return the DTO to the controller.
  3. Use a DTO projection query that selects exactly the needed columns.
@Transactional(readOnly = true)
public OrderDetailsDto getOrder(Long id) {
    Order order = orderRepository.findWithItemsById(id)       // JOIN FETCH query
            .orElseThrow(() -> new OrderNotFoundException(id));
    return OrderDetailsDto.from(order);                       // mapped while the Session is open
}

Fixes to Avoid

"Fix"Problem
Change to FetchType.EAGERevery query now loads the association; causes N+1 elsewhere
spring.jpa.open-in-view=true (Spring Boot default)keeps the connection busy while the view/JSON renders; hides N+1 queries in controllers
hibernate.enable_lazy_load_no_trans=trueopens a new connection and Session for every lazy access: N+1 with extra connections
Calling Hibernate.initialize() everywhereworks, but runs one extra query per association

Tip: Spring Boot logs a warning at startup: spring.jpa.open-in-view is enabled by default. Set spring.jpa.open-in-view=false in new projects so lazy-loading mistakes show up in development, not as slow pages in production.