-
[스프링부트/웹 애플리케이션 개발]API 개발 고급 - 컬렉션 조회 최적화 -1,2스프링&스프링부트 2023. 1. 13. 14:03
- 컬렉션인 일대다 관계 (OneToMany)를 조회하고, 최적화하는 방법
- 주문내역에서 추가로 주문한 상품 정보를 추가로 조회
- Order 기준으로 컬렉션인 OrderItem 와 Item 이 필요하다.
주문조회 V1: 엔티티 직접 노출
package jpabook.jpashop.api; import jpabook.jpashop.domain.Order; import jpabook.jpashop.domain.OrderItem; import jpabook.jpashop.repository.OrderRepository; import jpabook.jpashop.repository.OrderSearch; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController @RequiredArgsConstructor public class OrderApiController { private final OrderRepository orderRepository; @GetMapping("/api/v1/orders") public List<Order> ordersV1() { List<Order> all = orderRepository.findAllByString(new OrderSearch()); for (Order order : all) { order.getMember().getName(); //Lazy 강제 초기화 order.getDelivery().getAddress(); //Lazy 강제 초기환 List<OrderItem> orderItems = order.getOrderItems(); // for (OrderItem orderItem : orderItems) { // orderItem.getItem().getName(); // } orderItems.stream().forEach(o -> o.getItem().getName()); } return all; } }
- orderItem , item 관계를 직접 초기화하면 Hibernate5Module 설정에 의해 엔티티를 JSON으로 생성한다
- 양방향 연관관계면 무한 루프에 걸리지 않게 한곳에 @JsonIgnore 를 추가해야 한다
- 엔티티를 직접 노출하므로 좋은 방법은 아니다
주문조회 V2: 엔티티를 DTO로 변환
@GetMapping("/api/v2/orders") public List<OrderDto> ordersV2() { List<Order> orders = orderRepository.findAllByString(new OrderSearch()); List<OrderDto> collect = orders.stream() .map(o -> new OrderDto(o)) .collect(Collectors.toList()); return collect; } @Data static class OrderDto { private Long orderId; private String name; private LocalDateTime orderDate; private OrderStatus orderStatus; private Address address; private List<OrderItem> orderItems; public OrderDto(Order order) { orderId = order.getId(); name = order.getMember().getName(); orderDate = order.getOrderDate(); orderStatus = order.getStatus(); address = order.getDelivery().getAddress(); orderItems = order.getOrderItems(); } }
- orderItems > 엔티티이기 때문에 null
> OrderDto 코드 추가
public OrderDto(Order order) { orderId = order.getId(); name = order.getMember().getName(); orderDate = order.getOrderDate(); orderStatus = order.getStatus(); address = order.getDelivery().getAddress(); order.getOrderItems().stream().forEach(o -> o.getItem().getName()); //프록시 초기화 orderItems = order.getOrderItems(); }
- dto로 반환했을 때 dto 안에 엔티티가 있으면 안 된다
> 엔티티가 외부에 노출 됨
> 엔티티에 대한 의존을 완전히 끊어야한다
@Data static class OrderDto { private Long orderId; private String name; private LocalDateTime orderDate; private OrderStatus orderStatus; private Address address; //private List<OrderItem> orderItems; private List<OrderItemDto> orderItems; public OrderDto(Order order) { orderId = order.getId(); name = order.getMember().getName(); orderDate = order.getOrderDate(); orderStatus = order.getStatus(); address = order.getDelivery().getAddress(); order.getOrderItems().stream().forEach(o -> o.getItem().getName()); //프록시 초기화 orderItems = order.getOrderItems().stream() .map(orderItem -> new OrderItemDto(orderItem)) .collect(Collectors.toList()); } } @Getter static class OrderItemDto { private String itemName; private int orderPrice; private int count; public OrderItemDto(OrderItem orderItem) { itemName = orderItem.getItem().getName(); orderPrice = orderItem.getOrderPrice(); count = orderItem.getCount(); } }
- 지연로딩 많음 > 실행되는 sql의 양이 많음
- 지연 로딩은 영속성 컨텍스트에 있으면 영속성 컨텍스트에 있는 엔티티를 사용하고 없으면 SQL을 실행한다. 따라서 같은 영속성 컨텍스트에서 이미 로딩한 회원 엔티티를 추가로 조회하면 SQL을 실행하지 않는다.
728x90'스프링&스프링부트' 카테고리의 다른 글
[스프링부트/웹 애플리케이션 개발]API 개발 고급 - 컬렉션 조회 최적화 -4,5,6 (0) 2023.01.16 [스프링부트/웹 애플리케이션 개발]API 개발 고급 - 컬렉션 조회 최적화 -3 (0) 2023.01.13 [스프링부트/웹 애플리케이션 개발]API 개발 고급-5 (2) 2023.01.12 [스프링부트/웹 애플리케이션 개발]API 개발 고급-4 (0) 2023.01.12 [스프링부트/웹 애플리케이션 개발]API 개발 고급-3 (0) 2023.01.12