|
안녕하세요, 코딩하는곰입니다. 😊
JPA를 사용하다 보면 한 번쯤 마주치는 오류가 바로 LazyInitializationException인데요.
이 오류는 영속성 컨텍스트가 종료된 후 지연 로딩(Lazy Loading)을 시도할 때 발생합니다.
오늘은 이 문제의 근본적인 원인과 실무에서 적용 가능한 5가지 해결 방법을 상세히 설명드리겠습니다.
특히 Spring 환경에서의 해결책을 중점적으로 다룰 예정이니 끝까지 읽어주세요!
|
LazyInitializationException은 “no Session” 메시지와 함께 나타나며, 주로 다음 상황에서 발생합니다:
위 코드에서@Entitypublic class Order {@Id @GeneratedValueprivate Long id;@OneToMany(mappedBy = "order", fetch = FetchType.LAZY) // ← 지연 로딩 설정private List<OrderItem> items;}
order.getItems()를 트랜잭션 외부에서 호출하면 예외가 발생합니다.
🚀 개발자 커리어를 준비하고 있다면, (MySQL/MariaDB) INSERT 시 NULL과 DEFAULT 처리 완벽 가이드 - 코딩하는곰의 DB 이야기를 참고해보세요.
|
가장 간단하지만 성능 문제를 유발할 수 있는 방법입니다.
@OneToMany(mappedBy = "order", fetch = FetchType.EAGER) // 즉시 로딩private List<OrderItem> items;
# application.propertiesspring.jpa.open-in-view=true # 기본값이 true
| 장점 | 단점 |
|---|---|
| 뷰 레이어까지 지연 로딩 가능 | 장시간 연결 유지로 인한 리소스 낭비 |
| 설정 간편 | 성능 저하 가능성 |
PC나 모바일 브라우저에서 바로 실행되는 간편한 웹 스톱워치는 빠르게 시간 측정이 필요할 때 이상적인 도구입니다.
|
트랜잭션 내에서 명시적 초기화를 수행합니다.
@Transactionalpublic Order getOrderWithItems(Long orderId) {Order order = orderRepository.findById(orderId).orElseThrow();Hibernate.initialize(order.getItems()); // ← 강제 초기화return order;}
가장 안전한 방법으로, 엔티티 대신 DTO를 반환합니다.
public OrderDto getOrderDto(Long orderId) {return orderRepository.findById(orderId).map(order -> new OrderDto(order.getId(),order.getItems().stream() // ← 트랜잭션 내에서 처리.map(OrderItemDto::new).toList())).orElseThrow();}
JPQL의 fetch join을 사용하면 N+1 문제도 함께 해결됩니다.
@Query("SELECT o FROM Order o JOIN FETCH o.items WHERE o.id = :id")Optional<Order> findByIdWithItems(@Param("id") Long id);
📅 다양한 문화행사를 한눈에 보고 싶다면, 거문도백도은빛바다체험행사를 참고해보세요.
|
정리하자면, LazyInitializationException은 영속성 컨텍스트 라이프사이클과 로딩 전략의 이해가 부족할 때 발생합니다.
개인적으로는 DTO 변환이나 fetch join을 가장 추천드리며, 간혹 OSIV를 사용하는 팀도 있습니다.
여러분은 어떤 방법을 선호하시나요? 💬
코딩하는곰의 다음 포스팅에서는 N+1 문제의 3단계 해결법을 다룰 예정이니 기대해주세요!
(궁금한 점은 댓글로 남겨주시면 아는 범위에서 성실히 답변드리겠습니다 😊)
[블로그 구독하기][GitHub 링크] [관련 포스팅 보기]
기억력 감퇴를 막고 인지 능력을 향상시키고 싶다면, AI 힌트 기능이 있는 스도쿠 저니를 활용해보세요.
