실전! 스프링 부트와 JPA 활용2(API 개발과 성능 최적화)

Ch04. API 개발 고급(컬렉션 조회 최적화) - 주문 조회 V4(JPA에서 DTO 직접 조회)

webmaster 2021. 12. 21. 13:43
728x90
@Repository
@RequiredArgsConstructor
public class OrderQueryRepository { //화면에 의존적인 쿼리는 여기서 찾는다.

    private final EntityManager em;


    public List<OrderQueryDto> findOrderQueryDtos() {
        List<OrderQueryDto> result = findOrders(); //query 1번 -> N개
        result.forEach(o ->{
            List<OrderItemQueryDto> orderItems = findOrderItems(o.getOrderId()); //loof로 컬랙션을 직접채운다, query N번
            o.setOrderItems(orderItems);
        });
        return result;
    }

    private List<OrderItemQueryDto> findOrderItems(Long orderId) {
        return em.createQuery(
                "select new jpabook.jpashop.repository.order.query.OrderItemQueryDto(oi.order.id,i.name,oi.orderPrice,oi.count)"
                +" from OrderItem oi"
                +" join oi.item i"
                +" where oi.order.id = :orderId",OrderItemQueryDto.class
        ).setParameter("orderId",orderId)
                .getResultList();
    }

    private List<OrderQueryDto> findOrders() {
        return em.createQuery(
                "select new jpabook.jpashop.repository.order.query.OrderQueryDto(o.id,m.name,o.orderDate,o.status,d.address) from Order o"
                        + " join o.member m"
                        + " join o.delivery d", OrderQueryDto.class
        ).getResultList();
    }
}

OrderQueryDto

  • 객체에 바로 Select 할 수 있다.
  • Query: 루트 1번, 컬렉션 N 번 실행
  • ToOne(N:1, 1:1) 관계들을 먼저 조회하고, ToMany(1:N) 관계는 각각 별도로 처리한다.
    • 이런 방식을 선택한 이유는 다음과 같다.
    • ToOne 관계는 조인해도 데이터 row 수가 증가하지 않는다.
    • ToMany(1:N) 관계는 조인하면 row 수가 증가한다.
  • row 수가 증가하지 않는 ToOne 관계는 조인으로 최적화하기 쉬우므로 한 번에 조회하고, ToMany 관계는 최적화하기 어려우므로 findOrderItems() 같은 별도의 메서드로 조회한다.
  • OrderItemList를 Loof를 돌면서 채워줘야 된다.
728x90