예제
회원 클래스 안에 팀 객체가 있는 경우
회원을 조회 할 때 팀 객체까지 한 번에 같이 조회하는 것이 맞는가? 아니면 회원 테이블만 조회하는 게 맞는가?
이는 비즈니스 로직에 따라 설정을 하는 부분이다.
이 예제에서
만약 대부분의 경우 회원은 회원데이터만 필요하고 팀의 데이터는 필요 없다면 팀까지 한 번에 같이 끌어오는 건 손해다.
그래서 회원 엔티티가 아래와 같이 구성 되어있을 때

나는 상기 로직에 따라 회원만 먼저 조회하고 팀은 나중에 필요할 때 조회하겠다
라고 설정 하는 방법이 있는데 그걸 지연 로딩이라고 한다.

fetch = FetchType.Lazy 로 설정하면
회원이 조회될 때 팀 객체는 가짜 프록시로 생성이 되고
실제 팀이 조회될 때 프록시가 초기화되며 실제 팀을 조회하는 쿼리가 실행된다.
반대의 경우
대부분의 경우 회원과 팀의 데이터가 같이 조회되면 한 번에 끌어오도록 설정해야 한다.
fetch = FetchType.Eager로 설정하면 회원과 함께 팀이 조회가 되며
지연 로딩과 다르게 프록시가 아니라 실제 팀 객체가 생성된다.

어노테이션 별 기본값은
Eager : @ManyToOne, @OneToOne
Lazy : @OneToMany, @ManyToMany
이렇게 설정되어 있다.
하지만 실제 실무에서는 즉시 로딩은 거의 사용하지 않고 지연 로딩을 쓰는데
이유가 여러 가지 있다.
1. 즉시 로딩을 적용하면 예상치 못한 쿼리가 발생한다.
현재 예제는 조인이 1-2개지만 5개 이상만 돼도 말도 안 되는 긴 쿼리가 실행된다.
2. JPQL N+1 문제
JPQL로 select m from member m 쿼리를 실행한다고 했을 때
member만 조회하는 쿼리지만 Eager로 설정되어있으면 team도 조회하게 되는데
em.find로 찾을 때는 JPA가 내부적으로 최적화를 해서 한 번에 조회가 되지만, JPQL의 경우는 그렇지 않다.
이로 인해
member가 10명이면 team도 10번 조회 쿼리가 나가게 되는 것이다.
처음 쿼리가 1개가 나갔는데 추가 쿼리가 N개가 발생한다고 하여 N+1 문제가 발생한다고 말한다.
그렇다면 이 문제를 해결할 수 있는 방법?
1. 일단 전부 지연 로딩(Lazy)으로 설정
2. JPQL 쿼리에서 fetch join으로 조인을 건다.
'PROGRAMMING > JPA' 카테고리의 다른 글
| [JPA] Entity Manager & Entity Life Cycle (0) | 2021.11.18 |
|---|---|
| [JPA] 고아 객체 (Orphan Entity)와 orphanRemoval (0) | 2021.09.12 |
| [JPA] Persist 시점 에러 (0) | 2021.09.06 |
| [JPA] @MappedSuperclass (0) | 2021.09.05 |
| [JPA] @ID 와 @GENERATOR 전략 (0) | 2021.08.02 |