![[Spring] 즉시 로딩(Eager Loading)과 지연 로딩(Lazy Loading) 알아보기](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMAUPY%2Fbtr4vi4NzhN%2FxhOrcv5jWKQkvfxICJzPDk%2Fimg.png)
JPA에서 데이터를 조회할 때 사용하는 방식인 즉시 로딩과 지연 로딩에 대해 알아보겠습니다!
FetchType
FetchType은 하나의 엔티티를 조회할 때, 연관 엔티티를 어떻게 데이터베이스에서 가져올 것인지를 결정하는 옵션입니다. FetchType의 유형은 두 가지가 있습니다.
- Eager
- Lazy
@OneToOne과 @ManyToOne의 default FetchType은 Eager이고,
@ManyToOne과 @ManyToMany의 default FetchType은 Lazy입니다.
즉시 로딩(Eager Loading)
즉시로딩은 하나의 엔티티를 조회할 때, 연관 엔티티 전부를 한 번에 불러오는 것입니다.
- ex) @ManyToOne(fetch = FetchType.EAGER)
(예시)
멤버와 리뷰에 관계에 대해서 생각해 보겠습니다. 한 명의 멤버가 여러 개의 리뷰를 남길 수 있기에 멤버:리뷰 관계는 1:N 관계입니다.
@Entity
@Getter
public class Member {
@Id @GeneratedValue
@Column(name = "memberId")
private Long id;
private String name;
@JsonIgnore
@OneToMany(mappedBy = "member", cascade = CascadeType.ALL)
private List<MemberReview> review = new ArrayList<>();
}
@Entity
@Getter
public class MemberReview {
@Id @GeneratedValue
@Column(name = "reviewId")
private Long id;
private String content;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "userId")
private Member member;
}
MemberReview memberReview = em.find(MemberReview.class, reviewId);
리뷰 조회
select
memberrevi0_.review_id as review_i1_7_0_,
memberrevi0_.content as content2_7_0_,
memberrevi0_.user_id as user_id3_7_0_,
member1_.member_id as member_i1_6_1_,
member1_.name as name2_6_1_
from
member_review memberrevi0_
left outer join
member member1_
on memberrevi0_.user_id=member1_.member_id
where
memberrevi0_.review_id=?
리뷰를 조회하는 시점에 리뷰와 연관된 멤버까지 데이터베이스에서 불러오는 것을 확인할 수 있습니다.
지연 로딩(Lazy Loading)
지연 로딩은 필요 시점에 연관 엔티티를 불러오는 것입니다.
- ex) @MaynToOne(fetch = FetchType.LAZY)
위의 예시에서 MemberReview의 FetchType만 LAZY로 변경하였습니다.
@Entity
@Getter
public class MemberReview {
@Id @GeneratedValue
@Column(name = "reviewId")
private Long id;
private String content;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "userId")
private Member member;
}
MemberReview memberReview = em.find(MemberReview.class, reviewId);
System.out.println(memberReview.getMember().getId()); //이때, 멤버 조회 쿼리 실행
System.out.println(memberReview.getMember().getName());
select
memberrevi0_.review_id as review_i1_7_0_,
memberrevi0_.content as content2_7_0_,
memberrevi0_.user_id as user_id3_7_0_
from
member_review memberrevi0_
where
memberrevi0_.review_id=?
select
member0_.member_id as member_i1_6_0_,
member0_.name as name2_6_0_
from
member member0_
where
member0_.member_id=?
LAZY의 경우 멤버를 사용하는 시점에 멤버쿼리가 나가는 것을 확인할 수 있습니다.
어느 것을 사용해야 할까?
실무에서는 지연 로딩(Lazy Loading)을 주로 사용합니다.
그 이유는 예를 들어 MemberReview와 연관된 엔티티가 1개가 아닌 N개라 하겠습니다.
즉시로딩을 하게 되면, MemberReview 1개를 조회할 때마다 필요 없는 다른 N개의 엔티티를 조회하는 쿼리 N개가 생성됩니다. 즉, 1개의 JPQL문에 대해 총 쿼리문이 N+1개나 실행됩니다. 이를 N+1문제라고 합니다.
이경우 즉시로딩은 성능이 매우 떨어지기에 가급적 실무에서는 지연 로딩 사용을 권장합니다!
참고자료
JPA는 왜 지연 로딩을 사용할까?
JPA JPA에서 테이블 간 연관 관계는 객체의 참조를 통해 이뤄집니다. 서비스가 커질수록, 참조하는 객체가 많아지고, 객체가 가지는 데이터의 양이 많아집니다. 이렇게 객체가 커질수록, DB로부터
velog.io
'Spring' 카테고리의 다른 글
[Spring] 지연 로딩과 조회 성능 최적화 (0) | 2023.04.25 |
---|---|
[Spring] 양방향 순환참조 해결하기 (0) | 2023.04.15 |
[Spring] Cascade옵션 알아보기 (0) | 2023.03.15 |
[Spring] Bean Validation 알아보기 (1) | 2023.03.09 |
[Spring] DTO를 사용하는 이유를 알아보자 (0) | 2023.03.04 |
느리더라도 단단하게 성장하고자 합니다!
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!