본문 바로가기

PROGRAMMING/JPA

[JPA] 지연 로딩과 즉시 로딩

예제 

회원 클래스 안에 팀 객체가 있는 경우

회원을 조회 할 때 팀 객체까지 한 번에 같이 조회하는 것이 맞는가? 아니면 회원 테이블만 조회하는 게 맞는가?

 

이는 비즈니스 로직에 따라 설정을 하는 부분이다.

 

이 예제에서

만약 대부분의 경우 회원은 회원데이터만 필요하고 팀의 데이터는 필요 없다면 팀까지 한 번에 같이 끌어오는 건 손해다.

 

 

그래서 회원 엔티티가 아래와 같이 구성 되어있을 때

 

 

나는 상기 로직에 따라 회원만 먼저 조회하고 팀은 나중에 필요할 때 조회하겠다

라고 설정 하는 방법이 있는데 그걸 지연 로딩이라고 한다.

 

 

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