728x90
지난 글에 이어서 이번에는 엔티티를 Dto로 변환하여 응답을 내려주는 것을 할 것이다.
01. 코드 작성
다음과 ordersV2 를 작성한다.
@GetMapping("/api/v2/simple-orders")
public List<SimpleOrderDto> ordersV2() {
List<Order> orders = orderRepository.findAllByString(new OrderSearch());
List<SimpleOrderDto> result = orders.stream()
.map(o -> new SimpleOrderDto(o)) // order를 dto로 변환함
.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();
orderDate = order.getOrderDate();
orderStatus = order.getStatus();
address = order.getDelivery().getAddress();
}
}
stream을 이용하여 Order 엔티티를 Dto로 변환한다.
Dto 클래스에서는 응답으로 내려줄 필드들을 작성하고 해당 필드들을 포함하는 생성자를 작성한다. 매개변수로는 Order를 받는다.
address는 value object 이다. 엔티티가 아니다.
응답은 다음과 같다.
이전 V1 에서는 엔티티를 그대로 노출하여 필드명이 id 였던 것이, V2에서는 Dto 클래스를 응답 결과를 만들고 반환했기 때문에 orderId로 변한 것을 볼 수 있다.
02. 문제점
앞서 작성한 V1와 지금 작성한 V2 에는 모두 치명적인 단점이 있다. 그것은 바로 지연로딩으로 인한 DB 호출이 너무 많이 된다는 것이다.
Member, Delivery, Order 이 3개의 테이블을 건드려야 하는 상황이다.
SimpleOrderDto의 생성자에서, name=order.getMember().getName()
중 .getName()
에서 지연로딩이 초기화 된다. 이 말은, id를 갖고 영속성 컨텍스트에서 데이터를 찾는데, 없으면 DB에 쿼리를 보낸다는 것이다.
이 API를 호출하면 쿼리는 총 5번 나간다.
List orders = orderRepository.findAllByString(new OrderSearch());
위 코드에서 쿼리가 한 번 나간다. 결과로 Order는 2개가 반환된다. new SimpleOrderDto(o)에서 지연로딩을 초기화 하며 총 2번 돌고, Member 테이블, Delivery 테이블에 각각 쿼리가 2번 나간다.
이것을 N+1 문제라고 한다. 첫번째 쿼리의 결과로 N번이 추가로 실행된다.
영속성 컨텍스트에 값이 있으면 DB에 쿼리가 나가지 않는다.
728x90
'API' 카테고리의 다른 글
API 개발 고급 - 간단한 주문 조회 V1: 엔티티를 직접 노출 (0) | 2024.02.05 |
---|---|
API 개발 기본 (2) | 2024.02.02 |