JPA에서 DTO직접 조회 , 컬렉션 조회 최적화
V4에 문제였던 쿼리 n+1 문제 개선
@GetMapping("/api/v5/orders")
public List<orderQueryDto> ordersV5(){
return orderQuertRepository.findAllByDto_Optimization();
}
1.order 가져오기
public List<orderQueryDto> findORders(){
return em.createQuery(
"select new jpabook~orderQueryDto(o.id , m.name , o.orderDate , o.status , d.address)" +
"from order o "+
"join o.member m" +
"join o.delivery d" , orderQueryDto.class )
.getResultList();
}
2.orderItem 가져오기 V5 (v4에 n+1 해결)
public List<orderQueryDto> findAllByDto_Oprimization(){
List<orderQuertyDto> result = findOrders();
//일단 Order를 가져온다.
List<Long> orderIds = result.stream()
.map(o -> o.getOrderId())
.collect(collectors.toList());
//가져온 order의 ID들을 List로 뽑아내기
List<orderItemQueryDto> orderItems = em.createQuery(
"select new jpabook~orderItemQueryDto(oi.order.id , i.name , oi.orderPrice , oi.count)" +
"from orderItem oi" +
"join oi.item i" +
"where oi.order.id in :orderIIds ", orderItemQuertDto.class)
.setParameter("orderIds" , orderIds)
.getResultList();
//가져온 orderIds(collection)을 IN절 뒤에 파라미터로 넣으면 In절에 값이 한번에 다 들어가게 된다.
}
Map<Long , List<orderItemQuertDto>> orderItemMap = orderItems.stream()
.collect(collectors.groupingBy(orderItemQuery::getOrderId)) //자바의 메소드 참조
-orderItems를 map으로 변경
-getOrderId를 키값으로 List값을 Value값으로 사용 리스트를 반환한다.
result.forEach(o -> o.setOrderItems(orderItemMap.get(o.getOrderId())));
result를 forEach를 적용하여 map과 일치하는 id값의 List로 각 order에 넣어준다.
메모리 단계로 가져와서 분배하는것이 핵심
in을 이요한 쿼리를 1번만 실행, 그 값을 map으로 바꾸어 각 order에 set해주어 return
order가져올때 1번 , OrderItem가져올때 1번 총 2번 쿼리가 나가게 된다.
'JPA' 카테고리의 다른 글
| 3월 6일 JPA API 개발 고급 정리 (0) | 2023.03.06 |
|---|---|
| 3월 6일 JPA 주문조회 V6 (0) | 2023.03.06 |
| 3월 3일 JPA 주문조회 v4 (0) | 2023.03.03 |
| 2월 27일 주문조회 V3.1 (0) | 2023.02.27 |
| 2월 27일 JPA 주문조회 V3 (0) | 2023.02.27 |