<aside> ❗

V1 - 엔티티 직접 노출

@GetMapping("/api/v1/orders")
    public List<Order> orderV1() {
        List<Order> all = orderRepository.findAllByString(new OrderSearch());
        for (Order order : all) {
            order.getMember().getName();
            order.getDelivery().getAddress();

            List<OrderItem> orderOrderItems = order.getOrderItems();
            for (OrderItem orderItem : orderOrderItems) {
                orderItem.getItem().getName();
            }
        }
        return all;
    }

<aside> ❗

V2 - 엔티티를 DTO로 변환

@GetMapping("/api/v2/orders")
    public List<OrderDto> orderV2() {
        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<OrderItemDto> orderItems;

        public OrderDto(Order order) {
            this.orderId = order.getId();
            this.name = order.getMember().getName();
            this.orderDate = order.getOrderDate();
            this.orderStatus = order.getOrderStatus();
            this.address = order.getDelivery().getAddress();
            this.orderItems = order.getOrderItems().stream()
                    .map(orderItem -> new OrderItemDto(orderItem))
                    .collect(Collectors.toList());
        }
    }

    @Data
    static class OrderItemDto {
        private String itemName;
        private int orderPrice;
        private int count;

        public OrderItemDto(OrderItem orderItem) {
            this.itemName = orderItem.getItem().getName();
            this.orderPrice = orderItem.getItem().getPrice();
            this.count = orderItem.getCount();
        }
    }

[참고]

<aside> ❗

V3 - 엔티티를 DTO로 변환 - 페치 조인 최적화

DISTINCT 키워드

public List<Order> findAllWitehItem() {
        return em.createQuery("select DISTINCT o from Order o join fetch o.member m join fetch o.delivery d join fetch o.orderItems oi join fetch oi.item", Order.class)
                .getResultList();
    }
// v2와 동일
@GetMapping("/api/v3/orders")
    public List<OrderDto> orderV3() {
        List<Order> orders = orderRepository.findAllWitehItem();

        List<OrderDto> collect = orders.stream().map(o -> new OrderDto(o)).collect(Collectors.toList());
        return collect;
    }

[참고]

<aside> ❗

V3.1 - 엔티티를 DTO로 변환 - 페이징 한계 돌파

한계 돌파



  jpa:
    properties:
      hibernate:
        default_batch_fetch_size: 

ToMany는 해당 필드에 @BatchSize() 애너테이션을 붙이고

@BatchSize(size = 1000)
    @OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
    private List<OrderItem> orderItems = new ArrayList<>();

ToOne인 경우 해당 엔티티 상단에 @BatchSize() 애너테이션을 붙여야 한다.

@BatchSize(size = 1000)
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "dtype")
@Getter @Setter
public abstract class Item { ... }

[처리 과정]

  1. Order 정보를 페치 조인을 통해서 가져온다.
  2. 지연로딩으로 설정된 OrderItems 엔티티에 접근 시, Order 정보(OrderId)를 이용하여 OrderItems 100개에 대하여 IN 쿼리를 수행한다. 만약 다 가져오지 못했다면 반복 수행 (BatchSize = 100) → 가지고 와서 영속성 컨텍스트에 저장
select oi1_0.order_id,oi1_0.order_item_id,oi1_0.count,oi1_0.item_id,oi1_0.order_price 
from order_item oi1_0 
where oi1_0.order_id in (1,2)
  1. OrderItems의 Item 엔티티에 접근시 OrderItems 정보(orderItemsId)를 이용하여 Items 100개에 대하여 IN 쿼리를 수행한다. 만약 가져오지 못했다면 반복 수행 → 가지고 와서 영속성 컨텍스트에 저장
select i1_0.item_id,i1_0.dtype,i1_0.name,i1_0.price,i1_0.stock_quantity,i1_0.artist,i1_0.etc,i1_0.author,i1_0.isbn,i1_0.actor,i1_0.director 
from item i1_0 
where i1_0.item_id in (1,2,3,4)

[참고]

</aside>

<aside> ❗

정리

spring:
	jpa:
		properties:
			hibernate:
				default_batch_fetch_size: 1000

[장점]

결론

[참고]

</aside>

<aside> ❗

</aside>

<aside> ❗

</aside>

<aside> ❗

</aside>

<aside> ❗

</aside>