-
[JPA] LazyInitializationException 발생!Spring/JPA 2024. 2. 14. 13:56728x90반응형
예외 발생 이유
세션이 사라진 후 지연 로딩(LAZY) 상태에서 프록시 초기화가 불가능하기 때문에 발생하는 예외
지연 로딩 ( FetchType.LAZY )
지연 로딩을 하는 이유는 JPA에서 발생하는 문제 중 가장 유명한 N + 1 문제를 해결하기 위함이다.
지연 로딩은 한번에 연관된 데이터까지 한번에 불러오는 것이 아닌 연관된 데이터를 필요한 시점에 그때 그때 불러오는 것이다.
그래서 왜 지연 로딩을 쓰는가?
예를 들어 Member과 Team테이블이 있고 Member와 Team는 N:1 관계가 있다.
이때 즉시 로딩(EAGER)을 하게 된다면 Team을 조회 시 해당 Team을 가진 모든 Member를 하나씩 조회하게 된다.
분명 Team 1개를 조회했는데 Team에 속한 Member N개의 조회 쿼리가 나가는 문제를 N + 1 문제라고 하며 이런 문제를 지연 로딩(LAZY)로 쉽게 해결이 가능하기 때문이다.
해결 방안
- @Transactional Annotation
- Fetch Join
- @EntityGraph
@Transactional ✔
해당 예외의 근본적인 문제는 영속성 컨텍스트가 종료되고 트랜젝션이 끝났을 때 일어나는 예외이기 때문에 해당 문제를 근복적으로 해결할 수 있는 가장 좋은 해결 방안이다.
Fetch Join
Fetch Join은 JPQL에서 성능 최적화를 위해 제공하는 Join의 종류이다.
이는 연관된 Entity와 Collection을 한번에 조회할 수 있도록 해주는 기능이다.
Fetch Join을 사용하는 경우 Join 대상에는 별칭을 줄 수 없다.
// 해당 내용은 JPA 표준에서는 지원하지 않지만 // Hibernate 및 몇몇 구현체는 별칭을 지원하기 때문에 오류가 발생하지 않는다. [❌] select t from Team t JOIN FETCH t.members m [⭕] select t from Team t JOIN FETCH t.members
@EntityGraph
EntityGraph는 즉시 로딩(EAGER)와 다를 바 없지만 Distinct 설정이 가능하다는 장점이 있다.
결국 Left Outer Join으로 데이터를 읽어오게 된다.
// Member의 FetchSize는 LAZY이다. public interface MemberRepository extends JpaRepository<Member, Long>{ @EntityGraph(attributePaths = {"team"}) List<Member> findEntityGraph(); } select member0_.member_id ~, team1_.team_id ~, member0_.username ~, member0_.team_id ~, team1_.name from member member0_ left outer join team team1_ on member0_.team1_id = team1_.team_id
728x90반응형'Spring > JPA' 카테고리의 다른 글