Order와 Member는 @ManyToOne,
Order와 OrderItem은 @OneToMany 관계이다.
OrderDto는 아래와 같다.
@Getter
static class OrderDto {
private Long orderId;
private String name;
private LocalDateTime orderDate;
private OrderStatus orderStatus;
private Address address;
private List<OrderItemDto> orderItems;
public OrderDto(Order order) {
orderId = order.getId();
name = order.getMember().getName();
orderDate = order.getOrderDate();
orderStatus = order.getStatus();
address = order.getDelivery().getAddress();
orderItems = order.getOrderItems().stream()
.map(OrderItemDto::new)
.collect(toList());
;
}
}
@Getter
static class OrderItemDto {
private String itemName;//상품 명
private int orderPrice;//주문 가격
private int count;//주문 수량
public OrderItemDto(OrderItem orderItem) {
itemName = orderItem.getItem().getName();
orderPrice = orderItem.getOrderPrice();
count = orderItem.getCount();
}
}
복잡성을 줄이기 위해 Order와 OrderItem의 1:N관계에 대한 쿼리만 분석해보도록 하겠다.
Order Entity의 경우 자신과 연관되어 있는 엔티티들은 fetchType=Lazy로 설정되어 있으므로, Order 엔티티를 가져와 영속성 컨텍스트에 보관하고 추후에 연관된 엔티티가 필요한 시점에 가져온다.
for문을 돌면서, 각 Order.getOrderItems()를 호출할때 비로소 지연로딩으로 OrderItem을 조회하기 위한 쿼리가 나간다. 더하여 각 OrderItem.getItem을 할 때마다 Item을 조회하기 위한 쿼리가 나간다.
Order이 2개, 각 Order마다 OrderItem이 2개, 각 OrderItem은 1개의 Item을 가진다고 하면,
Order를 조회하기 위한 쿼리 1개 --> 결과 2개의 Order
각 Order마다 연관된 OrderItem을 조회하기 위한 쿼리 2개.
각 OrderItem마다 연관된 Item을 조회하기 위한 쿼리 4개.
우리는 Order를 조회하기 위한 1번의 쿼리를 위한 (1+2+4)=7번의 쿼리가 필요한 상황이다.
이제 1번의 쿼리를 위해 N번의 쿼리가 추가적으로 나가는 N+1문제를 해결해보도록 하자.
순서
1. Order와 Member, Order와 Delivery의 @toOne 관계를 fetch join으로 성능 최적화.
2. Order와 OrderItem의 @toMany관계의 최적화 2가지 방법 비교
(fetch join, @BatchSize)