오봉이와 함께하는 개발 블로그
JPA 2 - 주문 조회 V1 : 엔티티 직접 노출 본문
728x90
주문 조회 V1: 엔티티 직접 노출
주문내역에서 추가로 주문한 상품 정보를 추가로 조회하자.Order
기준으로 컬렉션인 OrderItem
와 Item
이 필요하다.
앞의 예제에서는 XtoOne
(OneToOne
, ManyToOne
)관계만 있었다.XtoOne
관계에서는 fetch join
을 사용해서 쉽게 해결할 수 있지만 일대다 관계는 얘기가 다르다.
예를 들어 1:3 관계라고 하면 1을 조회하기 위해 쿼리가 3개 더 추가되는 문제가 있고, 이런 경우 최적화하기 어렵다는 문제가 있다.
이번에는 컬렉션인 일대다 관계(OneToMany
)를 조회하고, 최적화하는 방법을 알아보자.
/**
* V1. 엔티티 직접 노출
* - 엔티티가 변하면 API 스펙이 변한다.
* - 트랜잭션 안에서 지연 로딩 필요
* - 양방향 연관관계 문제
*
* V2. 엔티티를 조회해서 DTO로 변환(fetch join 사용X)
* - 트랜잭션 안에서 지연 로딩 필요
*
* V3. 엔티티를 조회해서 DTO로 변환(fetch join 사용O)
* - 페이징 시에는 N 부분을 포기해야함(대신에 batch fetch size? 옵션 주면 N -> 1 쿼리로 변경 가능)
*
*V4.JPA에서 DTO로 바로 조회, 컬렉션 N 조회 (1+NQuery)
* - 페이징 가능
*
*V5.JPA에서 DTO로 바로 조회, 컬렉션 1 조회 최적화 버전 (1+1Query)
* - 페이징 가능
*
* V6. JPA에서 DTO로 바로 조회, 플랫 데이터(1Query) (1 Query)
* - 페이징 불가능... *
*/
@RestController
@RequiredArgsConstructor
public class OrderApiController {
private final OrderRepository orderRepository;
@GetMapping("/api/v1/orders")
public List<Order> ordersV1() {
List<Order> all = orderRepository.findAllByCriteria(new OrderSearch());
for (Order order : all) {
order.getMember().getName(); // LAZY 강제 초기화
order.getDelivery().getAddress(); // LAZY 강제 초기화
List<OrderItem> orderItems = order.getOrderItems();
orderItems.stream().forEach(o -> o.getItem().getName()); // LAZY 강제 초기화
}
return all;
}
}
- orderItem, item관계를 직접 초기화하면 Hibernate5Module설정에 의해 엔티티를 JSON으로 생성한다.
- 양방향 연관관계면 무한 루프에 걸리지 않게 한곳에 @JsonIgnore를 추가해야 한다.
- 엔티티를 직접 노출하므로 좋은 방법은 아니다.
Hibernate5Module
의 기본 설정 자체가 프록시 객체는 데이터를 뿌리지 않기 때문에 Order
와 연관된 모든 정보를 출력하기 위해서 Member
, Delivery
, OrderItems
모두 강제 초기화를 해주었다.
[
{
"id": 4,
"member": {
"id": 1,
"name": "userA",
"address": {
"city": "서울",
"street": "1",
"zipcode": "1111"
}
},
"orderItems": [
{
"id": 6,
"item": {
"id": 2,
"name": "JPA1 BOOK",
"price": 10000,
"stockQuantity": 99,
"categories": null,
"author": null,
"isbn": null
},
"orderPrice": 10000,
"count": 1,
"totalPrice": 10000
},
{
"id": 7,
"item": {
"id": 3,
"name": "JPA2 BOOK",
"price": 20000,
"stockQuantity": 98,
"categories": null,
"author": null,
"isbn": null
},
"orderPrice": 20000,
"count": 2,
"totalPrice": 40000
}
],
"delivery": {
"id": 5,
"address": {
"city": "서울",
"street": "1",
"zipcode": "1111"
},
"status": null
},
"orderDate": "2022-09-05T18:12:07.978121",
"status": "ORDER",
"totalPrice": 50000
},
{
"id": 11,
"member": {
"id": 8,
"name": "userB",
"address": {
"city": "진주",
"street": "2",
"zipcode": "2222"
}
},
"orderItems": [
{
"id": 13,
"item": {
"id": 9,
"name": "SPRING1 BOOK",
"price": 20000,
"stockQuantity": 197,
"categories": null,
"author": null,
"isbn": null
},
"orderPrice": 20000,
"count": 3,
"totalPrice": 60000
},
{
"id": 14,
"item": {
"id": 10,
"name": "SPRING2 BOOK",
"price": 40000,
"stockQuantity": 296,
"categories": null,
"author": null,
"isbn": null
},
"orderPrice": 40000,
"count": 4,
"totalPrice": 160000
}
],
"delivery": {
"id": 12,
"address": {
"city": "진주",
"street": "2",
"zipcode": "2222"
},
"status": null
},
"orderDate": "2022-09-05T18:12:08.035307",
"status": "ORDER",
"totalPrice": 220000
}
]
인프런 김영한 지식공유자님 강의 - 실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
728x90
'BE > JPA' 카테고리의 다른 글
JPA 2 - 주문 조회V3 : 엔티티를 DTO로 변환(페치 조인 최적화) (0) | 2022.09.05 |
---|---|
JPA 2 - 주문 조회V2 : 엔티티를 DTO로 변환 (0) | 2022.09.05 |
JPA 2 - 간단한 주문 조회 V4 : JPA에서 DTO로 바로 조회 (0) | 2022.09.05 |
JPA 2 - 간단한 주문 조회 V3 : 엔티티를 DTO로 변환 (페치 조인 최적화) (0) | 2022.09.04 |
JPA 2 - 간단한 주문 조회 V2 : 엔티티를 DTO로 변환 (0) | 2022.09.04 |
Comments