Java
JPA FetchType.EAGER와 LAZY의 차이 알아보기
누구세연
2024. 11. 22. 21:49
JPA를 사용할 때 @OneToMany, @ManyToOne 등 연관 관계를 매핑할 때 종종 등장하는 옵션이 있습니다. 바로 FetchType.EAGER와 FetchType.LAZY입니다. 이 두 옵션은 연관된 엔티티 데이터를 언제 로딩할지를 결정하며, 올바르게 설정하지 않으면 성능 문제를 일으킬 수 있습니다. 이번 글에서는 두 FetchType의 차이와 실무에서의 사용법을 다뤄보겠습니다.
FetchType이란?
FetchType은 JPA에서 엔티티의 연관된 데이터를 가져오는 방식을 정의합니다.
기본적으로 JPA는 두 가지 FetchType을 제공합니다:
- EAGER (즉시 로딩)
- LAZY (지연 로딩)
FetchType.EAGER (즉시 로딩)
- 즉시 로딩은 엔티티를 조회할 때 연관된 엔티티 데이터도 즉시 가져옵니다.
- 예를 들어 A 엔티티가 B 엔티티와 연관되어 있다면, A를 조회할 때 자동으로 B도 조회됩니다.
@Entity
public class A {
@ManyToOne(fetch = FetchType.EAGER)
private B b;
}
실행 시 SQL
SELECT * FROM A;
SELECT * FROM B WHERE B.ID = ...; -- 연관된 B도 즉시 로딩
장점
- 연관된 데이터를 항상 사용한다면 편리합니다.
- 쿼리 횟수가 줄어드는 경우도 있습니다.
단점
- 필요하지 않은 데이터를 가져오면서 불필요한 리소스가 낭비될 수 있습니다.
- N+1 문제를 유발할 가능성이 큽니다.
2. FetchType.LAZY (지연 로딩)
- 지연 로딩은 연관된 데이터를 실제로 접근할 때까지 가져오지 않습니다.
- 기본적으로 프록시 객체를 반환하며, 해당 객체에 접근하는 순간 쿼리가 실행됩니다.
@Entity
public class A {
@ManyToOne(fetch = FetchType.LAZY)
private B b;
}
실행 시 SQL
SELECT * FROM A; -- B에 대한 쿼리는 실행되지 않음
`A.getB()`를 호출하면 그때서야 연관된 B를 조회합니다.
SELECT * FROM B WHERE B.ID = ...;
장점
- 초기 로딩 시간이 줄어듭니다.
- 필요할 때만 데이터를 가져와 효율적입니다.
단점
- 예상치 못한 시점에 추가 쿼리가 발생할 수 있습니다.
- Hibernate의 LazyInitializationException을 주의해야 합니다.
EAGER vs LAZY의 비교
특징 | FetchType.EAGER | FetchType.LAZY |
데이터 로딩 시점 | 엔티티 조회 시 즉시 로딩 | 연관 엔티티 접근 시 로딩 |
장점 | 간단한 코드, 연관 데이터 즉시 사용 가능 | 초기 로딩 시간 단축, 불필요한 데이터 배제 |
단점 | 불필요한 데이터 로딩, N+1 문제 발생 가능 | LazyInitializationException 위험 |
사용 사례 | 데이터가 항상 필요한 경우 | 연관 데이터가 가끔 필요한 경우 |
실무에서의 FetchType 설정 팁
- 기본 값 이해하기
- @ManyToOne, @OneToOne의 기본 FetchType은 EAGER입니다.
- @OneToMany, @ManyToMany의 기본 FetchType은 LAZY입니다.
- 기본 값을 변경하지 않아도 되는 경우가 많지만, 필요에 따라 설정을 명시적으로 변경하세요.
- Lazy 로딩을 기본으로 사용
- 대부분의 경우 연관 데이터를 즉시 로딩하지 않아도 됩니다.
- Lazy 로딩을 사용하고, 필요 시 join fetch 또는 **EntityGraph**를 활용해 데이터를 한 번에 로딩하세요.
- N+1 문제에 주의
- Lazy 로딩을 사용할 때, 연관 데이터를 반복적으로 접근하면 N+1 문제가 발생할 수 있습니다.
이를 방지하기 위해 JPQL의 fetch join이나 Hibernate batch size 설정을 활용하세요.
- Lazy 로딩을 사용할 때, 연관 데이터를 반복적으로 접근하면 N+1 문제가 발생할 수 있습니다.
💡JPA에서 FetchType.EAGER와 LAZY는 데이터 로딩 방식을 결정하는 중요한 설정입니다.
EAGER는 간편하지만, 성능 문제를 초래할 수 있습니다.
LAZY는 효율적이지만, 예기치 않은 쿼리와 LazyInitializationException에 주의해야 합니다.
실무에서는 기본적으로 LAZY를 선택하고, 필요한 경우 명시적으로 조정하는 전략을 추천합니다.
FetchType 설정을 올바르게 이해하고 적용하여 더 안정적이고 효율적인 애플리케이션을 만들어 보세요👀