org.hibernate.LazyInitializationException: could not initialize proxy
ID: java/hibernate-lazy-init
Version Compatibility
| Version | Status | Introduced | Deprecated | Notes |
|---|---|---|---|---|
| 17 | active | — | — | — |
Root Cause
LazyInitializationException occurs when code accesses a lazily-loaded Hibernate entity or collection outside of an active Hibernate Session. The proxy cannot fetch the data because the persistence context has already been closed.
genericWorkarounds
-
92% success Use a JPQL/HQL JOIN FETCH query or an EntityGraph to load the needed associations within the transaction
1. In your repository or DAO, write a query that explicitly fetches the required association: 'SELECT o FROM Order o JOIN FETCH o.items WHERE o.id = :id'. 2. Alternatively, use @EntityGraph on the repository method: @EntityGraph(attributePaths = {'items'}) Optional<Order> findById(Long id). 3. This loads the association in a single query within the transaction, so no lazy loading is needed later. 4. Only fetch what the specific use case needs — different service methods can use different fetch strategies. -
90% success Use DTOs or projections to transfer only the needed data out of the transaction boundary
1. Create a DTO class with only the fields needed by the caller. 2. Map entity data to the DTO within the @Transactional service method: new OrderDTO(order.getId(), order.getItems().stream().map(ItemDTO::from).toList()). 3. The DTO is a plain POJO — no lazy proxies, no Session needed. 4. Alternatively, use Spring Data projections (interface-based or class-based) to have the repository return DTOs directly. 5. This approach cleanly separates the persistence layer from the presentation layer.
Dead Ends
Common approaches that don't work:
-
Enabling spring.jpa.open-in-view=true (Open Session in View pattern)
50% fail
Open Session in View keeps the Hibernate Session open for the entire HTTP request lifecycle, including view rendering. This is considered an anti-pattern because: it leads to N+1 query problems in templates, database connections are held longer (pool exhaustion), lazy loads happen unpredictably during serialization, and it masks poor data access patterns.
-
Changing all FetchType.LAZY to FetchType.EAGER on entity relationships
65% fail
Eager fetching loads all related entities immediately, causing massive SQL joins and loading entire object graphs into memory. This leads to OutOfMemoryError for large datasets, extremely slow queries, and the classic N+1 problem replaced by a cartesian product problem.