티스토리 뷰

    @GetMapping("/api/v2/simple-orders")
    public List<SimpleOrderDto> orderV2(){
        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();
            orderDate = order.getOrderDate();
            orderStatus = order.getStatus();
            address = order.getDelivery().getAddress();
        }

    }

 

전편에서 v1으로 작성한 코드와 다르게 v2에서는 DTO를 생성하고 주입 후 리턴했다.

 

문제점

- LAZY로 인한 쿼리가 너무 많이 나가고 있다. (order 조회 후 DTO 당 lazy로 인한 member,delivery 쿼리 날림)

 

 

해결

A

    public List<Order> findAllWithMemberDelivery(){
        return em.createQuery("select o from Order o join fetch o.member m join fetch o.delivery d", Order.class).getResultList();
    }

 

- jpql에서 join fetch를 이용해 한번에 데이터를 받도록 레퍼지토리의 메서드를 만들어 준다.

- 한방 쿼리로 해결 되었다.

 

B

    public List<OrderSimpleQueryDTO> findOrderDtos(){
        return em.createQuery("select new jpabook2.jpashop2.repository.OrderSimpleQueryDTO(o.id, m.name, o.orderDate, o.status, d.address)" +
                                " from Order o "
                                +"join o.member m " +
                                "join o.delivery d", OrderSimpleQueryDTO.class).getResultList();
    }

 

a방식과 b방식의 차이가 있다.

 

A

  • enjtity를 뽑아내기 때문에 조회 중에 값을 바꿀 수 있다.
  • 원하지 않는 컬럼도 모두 뽑아낸다.

B

  • DTO 자체로 뽑기 때문에 조회 중에 값을 바꿀 수 없다.
  • 원하는 컬럼만 뽑아내어 성능이 최적화된다.(하지만 이 정도로 최적화 하는 것은 별 차이가 없어보인다.)
  • 레퍼지토리의 재사용성이 떨어진다. (API 스펙에 맞춰 레퍼지토리가 맞춰져 버린다.)

더 나은 방식으로 알아서 사용하면 된다.

 

B의 레퍼지토리 재사용성이 떨어지기 때문에 따로 만들어 관리하는 방식을 택한다(김영한 개발자님)

package jpabook2.jpashop2.repository.order.simplequery;

import jpabook2.jpashop2.domain.Address;
import jpabook2.jpashop2.domain.OrderStatus;
import lombok.Data;

import java.time.LocalDateTime;

@Data
public class OrderSimpleQueryDTO {
    private Long orderId;
    private String name;
    private LocalDateTime orderDate;
    private OrderStatus orderStatus;
    private Address address;

    public OrderSimpleQueryDTO(Long orderId, String name, LocalDateTime orderDate, OrderStatus orderStatus, Address address){
        this.orderId = orderId;
        this.name = name;
        this.orderDate = orderDate;
        this.orderStatus = orderStatus;
        this.address = address;
    }

}
package jpabook2.jpashop2.repository.order.simplequery;

import jakarta.persistence.EntityManager;
import jpabook2.jpashop2.repository.OrderSimpleQueryDTO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
@RequiredArgsConstructor
public class OrderSimpleQueryRepository {

    private final EntityManager em;

    public List<jpabook2.jpashop2.repository.OrderSimpleQueryDTO> findOrderDtos(){
        return em.createQuery("select new jpabook2.jpashop2.repository.OrderSimpleQueryDTO(o.id, m.name, o.orderDate, o.status, d.address)" +
                " from Order o "
                +"join o.member m " +
                "join o.delivery d", OrderSimpleQueryDTO.class).getResultList();
    }
}

이렇게 따로 관리해 준다.

 

1. 엔티티를 DTO로 변환하는 방법을 선택한다.

2. 필요하면 페치조인으로 성능을 최적화 한다. -> 대부분의 성능이슈가 해결된다.

3. 그래도 안되면 DTO로 직접 조회하는 방법을 사용한다.

4. 최후의 방법으로 JPA가 제공하는 네이티브 SQL이나 스프링 JDBC Template를 사용해서 SQL을 직접 사용한다.

 

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/10   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
글 보관함