Notice
Recent Posts
Recent Comments
Link
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 |
Tags
- java map 출력
- javaJVM
- 격파르타장점
- 비전공자sqld
- 코딩부트캠프후기
- 프로그래머스
- java map
- java기본자료형
- java list 저장
- java알고리즘
- 항해99후기
- java최솟값구하기
- 격파르타비전공자
- java set 저장
- java map 저장
- 인터프린터언어
- java list 출력
- 컴파일
- java 자료구조 활용
- 항해15기
- java알고리즘문제풀이
- java참조자료형
- 격파르타후기
- sqld자격증합격
- java set 출력
- 격파르타합격후기
- 프로그래머스제일작은수
- javaJRE
- 노베이스부트캠프
- 작은수제거하기
Archives
- Today
- Total
코딩과 결혼합니다
[JPA] 컬렉션 조회 최적화(1) 본문
728x90
이전에는 xToOne일 때의 조회 최적화를 해보았는데 이번에는 xToMany일 때 (컬렉션 조회) 최적화를 하는 방법에 대해서 정리하고자 한다.
DB 입장에서 1대 N 조인을 하면 조회하는 순간 데이터 결과가 N개만큼 커지게 된다. xToOne일 때에는 이 부분을 고려하지 않아도 되지만, 이러한 경우에는 최적화할 때 좀 더 고민해야 할 포인트가 많아진다.
@GetMapping("/api/v1/orders")
public List<Order> ordersV1() {
List<Order> all = orderRepository.findAllByString(new OrderSearch());
for (Order order : all) {
order.getMember().getName();
order.getDelivery().getAddress();
List<OrderItem> orderItems = order.getOrderItems();
orderItems.stream().forEach(o -> o.getItem().getName());
}
return all;
}
==========================================================================
//OrderItem Entity의 필드中
//양방향 관계 문제를 해결하기 위해 한 쪽에 @JsonIgnore
@JsonIgnore
@ManyToOne(fetch = LAZY)
@JoinColumn(name = "order_id")
private Order order;
Entity를 직접 노출하는 방법이다. Hibernate6 Module을 등록하고, LAZY 강제 초기화를 하여 필요한 데이터만을 뽑아온다.
(이전에 글로 적었지만 이렇게 초기화하지 않으면 모든 데이터들을 다 끌고 오게 된다. Hibernate6Module은 초기화된 데이터들만을 가져올 수 있게 동작한다.)
주문과 관련된 ORderItems를 다 가져와 또 이를 돌리며 Item 정보를 가져온다. Item은 이름만 필요로 하기 때문에 이것도 o.getItem().getName()과 같이 초기화를 해주었다.
➡️이 방법은 엔티티를 직접 노출하는 데에서 생기는 많은 문제들이 발생한다.
https://coding-s2-chaewon.tistory.com/252
@GetMapping("/api/v2/orders")
public List<OrderDto> ordersV2() {
List<Order> orders = orderRepository.findAllByString(new OrderSearch());
List<OrderDto> collect = orders.stream()
.map(o -> new OrderDto(o))
.collect(Collectors.toList());
return collect;
}
Entity를 DTO로 변환하는 방법이다.
@Getter
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) {
orderId = order.getId();
name = order.getMember().getName();
orderDate = order.getOrderDate();
orderStatus = order.getStatus();
address = order.getDelivery().getAddress();
orderItems = order.getOrderItems().stream()
.map(orderItem -> new OrderItemDto(orderItem))
.collect(Collectors.toList());
}
}
여기서 주의할 점은 Order 안에 OrderItems가 있는데 이것도 Entity를 그대로 반환하면 안 되고 Dto로 변환해야 한다는 것이다. 마찬가지로 OrderItemDto를 만들어 변환해 주었다. 엔티티에 대한 의존을 완전히 끊어야 한다.
@Getter
static class OrderItemDto {
private String itemName;
private int orderPrice;
private int count;
public OrderItemDto(OrderItem orderItem) {
itemName = orderItem.getItem().getName();
orderPrice = orderItem.getOrderPrice();
count = orderItem.getCount();
}
}
또한 프록시를 초기화하지 않고 돌리게 되면 orderItems의 값이 null이 나오게 되므로 필요한 데이터를 초기화해 주었다.
➡️ 이 방법은 쿼리가 굉장히 많이 나가게 된다. (영속성 컨텍스트에 있는 엔티티를 사용한다면 SQL을 실행하지 않는다.)
- order 1번
- member, address N번(order 조회 수만큼)
- orderItem N번(order 조회 수만큼)
- itemN번(orderItem 조회 수만큼)
'2세 > JPA' 카테고리의 다른 글
| [Spring Data JPA] 쿼리 메서드 (0) | 2024.02.28 |
|---|---|
| [Spring Data JPA] 순수 JPA와 Spring Data JPA (0) | 2024.02.27 |
| [JPA] 지연 로딩과 조회 성능 최적화(3) (1) | 2024.02.24 |
| [JPA] 영속성 전이(CASCADE), 고아 객체 (0) | 2024.02.23 |
| [JPA] 프록시 - 즉시 로딩과 지연 로딩 (0) | 2024.02.22 |