연관된 엔티티를 사용할 때 조회하는 지연 로딩
FetchType.EAGER 로 설정
일대일, 다대일로 매핑할 때 OrderItem
Entity 혹은 Order
Entity를 조회하려고 한다면 Order
Entity의 경우, 자신과 다대일로 매핑된 Member
Entity까지 조회하게 된다. 우리 쇼핑몰의 경우, 4개의 테이블을 조인해오지만 실제 비즈니스에서는 매핑되는 Entity의 개수가 훨씬 더 많을 것이다.
(OrderItem 하나를 조회했는데, 엄청나게 긴 쿼리문들이 나온다.)
그렇게 된다면 개발자는 쿼리가 어떻게 실행될지 예측할 수가 없다. 또한, 사용하지 않는 데이터도 한꺼번에 조회하므로 성능 문제도 있을 수 있다. 따라서 이럴 때는 즉시 로딩이 아닌 지연 로딩을 사용해야 한다.
OrderItem.java
package com.shop.entity;
import com.shop.constant.OrderStatus;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
import java.time.LocalDateTime;
@Entity
@Getter
@Setter
public class OrderItem {
@Id
@GeneratedValue
@Column(name = "order_item_id")
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "item_id")
private Item item;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "order_id")
private Order order;
private int orderPrice;
private int count;
private LocalDateTime regTime;
private LocalDateTime updateTime;
}
FetchType.LAZY
방식으로 지연 로딩 방식을 사용한다.
1. 만약, OrderItem을 조회한다고 하면 로딩되는 시점에 Lazy 로딩 설정이 되어있는 Order
, Item
Entity는 Proxy 객체로 가져오게 됨.
2. 이 후, 실제 객체를 사용하는 시점에 초기화가 됨. (DB에 쿼리가 나감)
즉, 사용되기 전까지는 데이터 로딩을 하지 않고, 실제 사용되는 시점에 조회 쿼리문이 실행된다. 이를 토대로 Cart
와 CartItem
, Order
도 지연 로딩을 설정해주었다.
📌
N + 1 issue
?
1번의 쿼리를 날렸을 때 의도하지 않은 N번의 쿼리가 추가적으로 실행되는 것을 의미한다.
실무에서는 복잡한 쿼리를 사용하기 위해 JPQL을 많이 사용하게 되는데 JPQL에서 만든 SQL을 통해 데이터를 조회할 때, EAGER 전략으로 Fetch하게 되면 해당 데이터의 연관 관계를 가진 하위 엔티티들을 추가적으로 조회하게 되는 것이다.
우리 프로젝트로 예를 들면 OrderItem
을 조회할 때, Order
Entity 를 각각 쿼리 날려서 가져오게 되는 것인데 만약 OrderItem
이 수천, 수만 개라면 엄청난 쿼리의 개수가 생성될 것이다.
❗ 지연 로딩일 경우 N+1 문제를 해결할 수 있는가?
FetchJoin
, EntityGraph
두 가지 방법으로 해결한다고 한다.FetchJoin
: 미리 두 테이블을 JOIN하여 한 번에 모든 데이터를 가져오면 N+1 문제가 발생하지 않는 것에서 착안<Fetch Join
의 단점>
Paging API(Pageable)
를 사용할 수 없다.Fetchjoin
을 사용할 수 없다.