간단한 주문 조회 V2: 엔티티를 DTO로 변환
API Specification을 명확하게 규정해야한다!
주문 조회 시 사용하는 DTO : SimpleOrderDto
@Data
static class SimpleOrderDto {
private Long orderId;
private String name;
private LocalDateTime orderDate; //주문시간 private OrderStatus orderStatus;
private OrderStatus orderStatus;
private Address address;
public SimpleOrderDto(Order order) {
orderId = order.getId();
name = order.getMember().getName();
orderDate = order.getOrderDate();
orderStatus = order.getStatus();
address = order.getDelivery().getAddress();
}
}
@GetMapping("/api/v2/simple-orders")
public List<SimpleOrderDto> ordersV2(){
List<Order> orders = orderRepository.findAllByCriteria(new OrderSearch());
//Order를 DTO로 변환!
List<SimpleOrderDto> result = orders.stream()
.map(o -> new SimpleOrderDto(o))
.collect(Collectors.toList());
return result;
}
람다식을 이용해서 리팩토링하면 다음처럼 코드 개선 가능 o->new SimpleOrderDto(o) : 생성자로 바로 넘기기 때문에
@GetMapping("/api/v2/simple-orders")
public List<SimpleOrderDto> ordersV2(){
return orderRepository.findAllByString(new OrderSearch)).stream()
.map(SimpleOrderDto::new)
.collect(toList());
}
V1, V2 문제점
지연 로딩으로 인해 DB 쿼리가 너무 많이 호출된다! V2 : Order, Member, Delivery 총 3개의 테이블 조회한다!
주문 조회 시 총 5번의 쿼리가 나간다! =>N+1 문제 발생‼️
Order 조회 : 주문 결과 2건
(루프1) DTO의 getMember().getName()로 MEMBER 조회
DTO의 getDelivery().getAddress()로 DELIVERY 조회
(루프2) DTO의 getMember().getName()로 MEMBER 조회
DTO의 getDelivery().getAddress()로 DELIVERY 조회
첫번째 쿼리(Order 조회) 나가면 이로 인해 N번만큼 쿼리 추가 실행 Order 조회(1) + N(2) = 1 + 회원 N + 배송 N =>Order가 총 2개 : 1+ 2 + 2 = 5(최악의 경우)
지연로딩은 영속성 컨텍스트에서 조회하므로, 이미 조회된 경우 쿼리를 생략한다. 실제로 회원 아이디를 동일하게 하고 주문하면 1 + 1+ 1 + 0 + 1 = 4 =>총 4번의 쿼리가 나가는 것을 확인할 수 있다.
Last updated
Was this helpful?