주문 조회 V6: JPA에서 DTO 직접 조회, 플랫 데이터 최적화
Order와 OrderItem, Item을 join해서 한번에 다 가져오도록 해본다! SQL에서는 flat하게 한줄로 나오기 때문에 이에 맞춰야한다.
OrderQueryDto로 바꾸고 싶다면 직접 중복을 제거해야한다.(a.k.a 노가다)
@GetMapping("/api/v6/orders")
public List<OrderFlatDto> ordersV6(){
return orderQueryRepository.findAllByDto_flat();
}
작전 : 한번에 다 join해서 쿼리가 한번만 실행되게 한다. =>당연히 중복 결과가 나온다! API Specification은 이전과 동일하게 해서 중복되는 데이터들은 직접 복잡한 쿼리들을 작성해서 제거한다.
그러면 한번의 쿼리로 원하는 데이터를 조회할 수 있다!
@GetMapping("/api/v6/orders")
public List<OrderQueryDto> ordersV6() {
List<OrderFlatDto> flats = orderQueryRepository.findAllByDto_flat();
return flats.stream()
.collect(groupingBy(o -> new OrderQueryDto(o.getOrderId(),
o.getName(), o.getOrderDate(), o.getOrderStatus(), o.getAddress()),
mapping(o -> new OrderItemQueryDto(o.getOrderId(),
o.getItemName(), o.getOrderPrice(), o.getCount()), toList())
)).entrySet().stream()
.map(e -> new OrderQueryDto(e.getKey().getOrderId(),
e.getKey().getName(), e.getKey().getOrderDate(), e.getKey().getOrderStatus(),
e.getKey().getAddress(), e.getValue()))
.collect(toList());
}
OrderFlatDto OrderDTO와 OrderItemDTO를 합친다!
package jpabook_v2.jpashop_v2.repository.order.query;
import jpabook_v2.jpashop_v2.domain.Address;
import jpabook_v2.jpashop_v2.domain.OrderStatus;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class OrderFlatDto {
private Long orderId;
private String name;
private LocalDateTime orderDate;
private OrderStatus orderStatus;
private Address address;
private String itemName;
private int orderPrice;
private int count;
public OrderFlatDto(Long orderId, String name, LocalDateTime orderDate, OrderStatus orderStatus, Address address, String itemName, int orderPrice, int count) {
this.orderId = orderId;
this.name = name;
this.orderDate = orderDate;
this.orderStatus = orderStatus;
this.address = address;
this.itemName = itemName;
this.orderPrice = orderPrice;
this.count = count;
}
}
OrderQueryRepository : 쿼리 작성
public List<OrderFlatDto> findAllByDto_flat() {
return em.createQuery(
"select new jpabook_v2.jpashop_v2.repository.order.query.OrderFlatDto(o.id, m.name, o.orderDate, o.status, d.address, i.name, oi.orderPrice, oi.count)" +
" from Order o" +
" join o.member m" +
" join o.delivery d" +
" join o.orderItems oi" +
" join oi.item i", OrderFlatDto.class)
.getResultList();
}
장점 : 쿼리 한번
단점
쿼리는 한번이지만 조인으로 인해 DB에서 애플리케이션에 전달하는 데이터에 중복 데이터가 추가되므로 상황에 따라 V5 보다 더 느릴 수 도 있음!
애플리케이션에서 추가 작업이 크다.
페이징 불가능 OrderFlatDto 나 OrderItems 관련 : 페이징 가능할 수도 있지만 Order에 대해서는 페이징 불가능. =>DB에서는 여전히 중복된 데이터가 포함된 테이블이 있기 때문. ex) DB : 4, 4, 11, 11 주문번호에 따라 이렇게 저장되있는데 우리가 원하는 것은 4,11 이다. 그래서 페이징으로 (0,2) 을 하면 4,4가 나와버린다.
Last updated
Was this helpful?