해당 글은 김영한 님의 자바 ORM 표준 JPA 프로그래밍을 참고하여 작성한 글입니다.
✅ 즉시 로딩과 지연 로딩
기능을 구현할 때 DB에서 가져오고 싶은 정보의 범위가 비즈니스 로직에 따라 다르다. 예를 들어, Member와 Team이라는 두 개의 entity가 연관 관계에 있을 때, 구현 목적에 따라 두 개의 데이터가 한 번에 조회되는 것이 좋을 수도 있고, 그렇지 않을 수도 있다. 이러한 상황을 JPA가 프록시와 지연 로딩을 통해 해결한다. 이전 글에서 프록시에 대해 알아보았고, 이 글에서는 지연 로딩에 대해 알아보겠다.
- JPA는 개발자가 연관된 Entity의 조회 시점을 선택할 수 있도록 다음 두 가지 방법을 제공한다.
- 즉시 로딩
- 지연 로딩
✅ 즉시 로딩 (EAGER LOADING)
- Entity를 조회할 때 연관된 Entity도 함께 조회한다.
- 설정 방법: @ManyToOne(fetch = FetchType.EAGER)
- 예: em.find(Member.class, "member1")를 호출할 때 Member Entity와 연관된 Team Entity도 함께 조회한다.
▶ 즉시 로딩 설정 코드
@Entity
public class Member {
...
@ManyToOne(fetch = FetchType.EAGER) //즉시 로딩
@JoinColumn(name = "TEAM_ID")
private Team team;
}
▶ 즉시 로딩 실행 코드
Member member = em.find(Member.class, "member1");
Team team = member.getTeam(); //객체 그래프 탐색
✅ 지연 로딩 (LAZY LOADING)
- 연관된 Entity를 프록시로 조회하고, 실제 사용할 때 초기화하면서 DB를 조회한다.
- 설정 방법: @ManyToOne(fetch = FetchType.LAZY)
- 예: member.getTeam().getName()처럼 조회한 Team Entity를 실제 사용하는 시점에 JPA가 SQL을 호출해서 Team Entity를 조회한다.
▶ 지연 로딩 설정 코드
@Entity
public class Member {
...
@ManyToOne(fetch = FetchType.LAZY) //지연 로딩
@JoinColumn(name = "TEAM_ID")
private Team team;
}
▶ 지연 로딩 실행 코드
Member member = em.find(Member.class, "member1");
Team team = member.getTeam(); //객체 그래프 탐색
team.getName(); //실제 team 객체를 사용하는 시점에 초기화(DB 조회)
✅ 즉시 로딩 주의 사항
- 실무에서는 가급적 지연 로딩만 사용하는 것이 권장된다.
- 즉시 로딩을 적용하면 예상하지 못한 SQL이 발생한다.
- 예: JOIN이 여러 개인 경우 성능에 부담이 된다.
- 즉시 로딩은 JPQL에서 N+1 문제를 일으킨다.
- N+1 문제: 1은 최초 쿼리, N은 최초 쿼리의 결과 개수로, 최초에 보낸 쿼리 한 번에 해당 결과 개수만큼 추가적으로 쿼리가 발생하는 것이다.
- JPQL에서 발생하는 이유: JPA는 find()의 경우 PK를 통해 가져오기 때문에 JPA가 내부적으로 최적화를 한다. 하지만 JPQL은 작성한 코드의 쿼리가 그대로 날아가기 때문에 Member만 조회한다. 이후 Member를 확인해 보니 즉시 로딩으로 설정되어 있는 Team을 조회하기 위해 N개의 쿼리가 추가로 나가게 된다.
- 지연 로딩을 사용하면 프록시를 사용하기 때문에 해당 문제가 발생하지 않는다.
- @ManyToOne, @OneToOne은 기본 값이 즉시 로딩이다.
- 이를 명시적으로 LAZY로 변경해서 사용해야 한다.
- @OneToMany, @ManyToMany는 기본 값이 지연 로딩이다.
✅ 지연 로딩의 활용
▶ 지연 로딩, 즉시 로딩의 활용 - 이론적 예시
- Member와 Team은 자주 함께 사용 ->
즉시 로딩 - Member와 Order는 가끔 사용 -> 지연 로딩
- Order와 Product는 자주 함께 사용 ->
즉시 로딩
- Member 조회 시 Order 프록시를 한 번 조회했다면?
- 해당 Order와 연관된 Product도 즉시 로딩으로 한 번에 가져온다.
▶ 지연 로딩 활용 - 실무
- 모든 연관관계에 지연 로딩을 사용한다.
- 실무에서 즉시 로딩을 사용하지 않는다.
- JPQL fetch join이나, 엔티티 그래프 기능을 사용한다.
📍 참고
'Programming > JPA' 카테고리의 다른 글
[JPA] 기본값 타입과 임베디드 타입 - 값 타입 (1) (1) | 2024.07.25 |
---|---|
[JPA] 영속성 전이(CASCADE)와 고아 객체 (1) | 2024.07.25 |
[JPA] 프록시 (1) | 2024.07.25 |
[JPA] 고급 매핑(상속관계 매핑) - 엔티티(Entity) 매핑 (7) (0) | 2024.07.25 |
[JPA] 다양한 연관관계 매핑 - 엔티티(Entity) 매핑 (6) (1) | 2024.07.25 |