참고 : [실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화] - 김영한
이번에는 엔티티 직접 노출이 아닌 정석 방법으로 DTO로 변환하여 반환해보자!
OrderSimpleApiController
...
/**
* V2. 엔티티를 조회해서 DTO로 변환(fetch join 사용X) * - 단점: 지연로딩으로 쿼리 N번 호출
*/
@GetMapping("api/v2/simple-orders")
public List<SimpleOrderDto> ordersV2(){ //원래는 List로 바로 반환 X. result로 감싸야 함.
List<Order> orders = orderRepository.findAllByString(new OrderSearch());
List<SimpleOrderDto> result = orders.stream()
.map(o->new SimpleOrderDto(o))
.collect(Collectors.toList());
return result;
}
@Data
static class SimpleOrderDto {
private Long orderId;
private String name;
private LocalDateTime orderDate;
private OrderStatus orderStatus;
private Address address;
public SimpleOrderDto(Order order) {
orderId = order.getId();
name=order.getMember().getName(); //LAZY 초기화
orderDate=order.getOrderDate();
orderStatus=order.getStatus();
address=order.getDelivery().getAddress(); //LAZY 초기화
}
}
...
orderRepository.findAllByString(new OrderSearch())를 통해 모든 주문 목록을 조회
조회된 Order 엔티티 리스트(orders)를 SimpleOrderDto로 변환
변환된 SimpleOrderDto 리스트를 클라이언트에게 반환
SimpleOrderDto

가급적으로는 이처럼 DTO로 바꿔서 반환해야한다!
- 쿼리가 총 1 + N + N번 실행된다. (v1과 쿼리수 결과는 같다.)
order조회 1번(order 조회 결과 수가 N이 된다.)order -> member지연 로딩 조회 N 번order -> delivery지연 로딩 조회 N 번- 예) order의 결과가 4개면 최악의 경우 1 + 4 + 4번 실행된다.(최악의 경우)
- 지연로딩은 영속성 컨텍스트에서 조회하므로, 이미 조회된 경우 쿼리를 생략한다.
간단한 쿼리일 경우 괜찮을 수 있지만,
N+1 문제가 발생한다.