Introduction
LazyInitializationException occurs when Hibernate tries to lazily load an entity association after the database session has been closed. This is one of the most common JPA/Hibernate errors, especially when lazy-loaded collections are accessed in the view layer or after the service method returns.
The error message "could not initialize proxy - no Session" indicates that the entity proxy cannot load its data because the EntityManager is no longer available.
Symptoms
- Application throws "org.hibernate.LazyInitializationException: could not initialize proxy - no Session"
- Error occurs when accessing a lazy-loaded collection in the controller or view layer
- Same code works in unit tests but fails in the full application
Common Causes
- Lazy-loaded collection accessed after the service transaction commits
- Entity returned from service layer and then its associations are accessed in the controller
- OSIV (Open Session in View) pattern disabled but code depends on it
Step-by-Step Fix
- 1.Use JOIN FETCH in the query to eagerly load associations: Load needed data in the original query.
- 2.```java
- 3.public interface UserRepository extends JpaRepository<User, Long> {
- 4.@Query("SELECT DISTINCT u FROM User u " +
- 5."LEFT JOIN FETCH u.orders " +
- 6."LEFT JOIN FETCH u.address " +
- 7."WHERE u.id = :id")
- 8.Optional<User> findByIdWithOrders(@Param("Long") id);
- 9.}
- 10.
` - 11.Use EntityGraph for dynamic fetch planning: Define fetch plans without modifying queries.
- 12.```java
- 13.@Entity
- 14.@NamedEntityGraph(name = "User.withOrders",
- 15.attributeNodes = @NamedAttributeNode("orders"))
- 16.public class User {
- 17.@OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
- 18.private List<Order> orders;
- 19.}
// Usage: EntityGraph<User> graph = entityManager.createEntityGraph(User.class); graph.addSubgraph("orders"); Map<String, Object> hints = Map.of("javax.persistence.fetchgraph", graph); User user = entityManager.find(User.class, id, hints); ```
- 1.Initialize collections within the transaction: Access lazy properties before the session closes.
- 2.```java
- 3.@Transactional(readOnly = true)
- 4.public UserDto getUserWithOrders(Long userId) {
- 5.User user = userRepository.findById(userId)
- 6..orElseThrow(() -> new NotFoundException("User not found"));
// Force initialization within transaction Hibernate.initialize(user.getOrders());
return UserDto.from(user); // Convert to DTO before leaving transaction } ```
Prevention
- Always convert entities to DTOs within the service layer (before session closes)
- Use JOIN FETCH or EntityGraph to explicitly load associations you need
- Avoid the Open Session in View pattern -- it hides lazy loading issues until production
- Use static analysis tools to detect lazy property access outside transactions