반응형
1. fetch join 을 이용해서 entity 조회 후 DTO로 변환
1 + N 문제 해결도 하고, 조인을 통해 쿼리 한번으로 조회 가능
- Controller 코드 (엔티티로 조회해 왔기 때문에 DTO로 수정 후 반환)
@GetMapping("/api/v3/simple-orders")
public List<SimpleOrderDto> ordersV3() {
List<Order> orders = orderRepository.findAllWithMemberDelivery();
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 초기화
}
}
- Repository 코드
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();
}
- JPA가 만들어 준 쿼리 (엔티티에 있는 모든 컬럼 조회)
select
order0_.order_id as order_id1_6_0_,
member1_.member_id as member_i1_4_1_,
delivery2_.delivery_id as delivery1_2_2_,
order0_.delivery_delivery_id as delivery4_6_0_,
order0_.member_id as member_i5_6_0_,
order0_.order_date as order_da2_6_0_,
order0_.status as status3_6_0_,
member1_.city as city2_4_1_,
member1_.street as street3_4_1_,
member1_.zipcode as zipcode4_4_1_,
member1_.name as name5_4_1_,
delivery2_.city as city2_2_2_,
delivery2_.street as street3_2_2_,
delivery2_.zipcode as zipcode4_2_2_,
delivery2_.status as status5_2_2_
from
orders order0_
inner join
member member1_
on order0_.member_id=member1_.member_id
inner join
delivery delivery2_
on order0_.delivery_delivery_id=delivery2_.delivery_id
2. DTO를 이용해서 필요한 컬럼만 뽑은 DTO로 조회
- Controller 코드 (DTO로 조회해왔기 떄문에 바로 반환 가능)
@GetMapping("/api/v4/simple-orders")
public List<OrderSimpleQueryDto> ordersV4() {
List<OrderSimpleQueryDto> result = orderSimplQueryRepository.findOrderDtos();
return result;
}
- Repository 코드 ( DTO 코드 생략, select 문에 new 이용하여 full package명을 붙여서 생성자로 DTO 생성 )
public List<OrderSimpleQueryDto> findOrderDtos() {
return em.createQuery(
"select new jpabook.jpashop.repository.order.simplequery.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();
}
- JPA가 만들어 준 쿼리 ( DTO에 있는 컬럼만 조회)
select
order0_.order_id as col_0_0_,
member1_.name as col_1_0_,
order0_.order_date as col_2_0_,
order0_.status as col_3_0_,
delivery2_.city as col_4_0_,
delivery2_.street as col_4_1_,
delivery2_.zipcode as col_4_2_
from
orders order0_
inner join
member member1_
on order0_.member_id=member1_.member_id
inner join
delivery delivery2_
on order0_.delivery_delivery_id=delivery2_.delivery_id
# 생각할 점
1번과 2번은 트레이드오프가 있음!
1번이 좀 더 깔끔.
2번은 화면 계층과 연관이 있고 엔티티 기준으로 쿼리를 수정하기에 좋지 않음(재사용 힘듬).
2번이 좀 더 성능이 빠를 수 있으나 큰 차이 없음.
확실하게 알아두려면 성능테스트 해봐야함!
인프런 - 실전! 스프링 부트와 JPA 활용2 - API개발과 성능최적화(김영한 강사님) 강의를 수강하며 정리한 글입니다 :)
반응형
'개발 > JPA' 카테고리의 다른 글
[JPA] 즉시로딩과 N+1 문제 (0) | 2022.10.24 |
---|---|
실전! 스프링 부트와 JPA활용 1 :: JPA와 DB 설정, 동작확인 - 테스트 실행 도중 에러 정리 (0) | 2022.10.22 |
[JPA] 지연로딩과 조회 성능 최적화 1 - xToOne (0) | 2022.04.18 |
[JPA] JPQL fetch join / 연관된 entity 한번에 select / distinct로 엔티티 중복 제거 / fetch join 페이징 안 될 때 @BatchSize 설정 (0) | 2022.04.12 |
[JPA] Hibernate Query Language(HQL) Projection / 하이버네이트 쿼리 언어 프로젝션 조회 / 특정 컬럼만 조회 / 예문 (0) | 2022.04.11 |
댓글