❰❰ API 개발 고급 - 지연 로딩과 조회 성능 최적화 ❱❱
도입
간단한 주문조회의 뜻
주문에 대해서
“주문+주문자+배송정보” 를 조회하자.
최적화 목표
- 지연로딩 기능으로 인한 문제를 해결해보자.
- 여러가지 방법들을 단계적으로 검토하여 장단점을 알아보자.
< 간단한 주문조회 >
[ (class) OrderSimpleApiController 만들기 ]
/* 클래스 */
@RestController
@RequiredArgsConstructor
public class OrderSimpleApiController {
private final OrderRepository orderRepository;
}
< 간단한 주문조회V1: 엔티티를 직접 노출 >
[ 살펴볼 점 ]
- 문제는 무엇인가?
- 해결책은 무엇인가?
- 해결책의 한계는 무엇인가?
[ V1: 엔티티를 직접 노출하는 메서드 ]
/* 엔티티 그대로 반환 */
//Lazy강제 초기화도 없이.
@GetMapping("/api/v1/simple-orders")
public List<Order> ordersV1() {
List<Order> all = orderRepository.findAllByString(new OrderSearch());
return all;
[ 0 ] 엔티티를 그대로 노출하는 경우, 문제점 2가지
- 1) 순환참조 문제
- 2) 지연로딩으로 인한 프록시엔티티 조회문제
[ 1 ] 순환참조 문제
문제점 생기는 이유
(Jackson라이브러리가 엔티티→ Json형태로 만들게 된다.)
그래서 엔티티를 조회하는데,,,
엔티티 내부에 엔티티도 조회하게 된다.
그런데, Order클래스에 Member 엔티티, Delivery 엔티티가 있다.
또한, 내부 엔티티가 원래의 엔티티를 참조하고 있다. (Order → Member → Order →
순환
)
→ 즉 순환구조이다.
따라서 계속 순환하면서, Json을 만들려고 하기에, 무한순환한다.
해결책과 한계점
- @JsonIgnore 어노테이션 걸어주기즉 원래 Order클래스로 돌아가는 참조에다가 JsonIgnore 걸어주기
- → 순환안되게, 되돌아가는데 걸어주기
- 한계점
- API스펙 변경 어려운 점들. 다양한 API스펙을 만들 수 없는 것들
[ 2 ] 지연로딩에서, 빈 깡통 프록시엔티티 조회
문제점
지연로딩인 경우, DB직접조회하지 않고(즉 지연하고)
하이버네이트에서 프록시엔티티를 생성해서 넣어준다.
(byteBuddy 라이브러리가 프록시엔티티를 만들어준다. 프록시엔티티 : ByteBuddyInterceptor 클래스)
→ 즉 초기화되지 않은 빈 깡통인 프록시객체를 조회하면 에러가 난다.
해결책과 한계점
4가지
- 해결책(1) 특정 모듈 사용하여 → null로 조회하기
- → 초기화되지 않은 프록시객체를 제외함. 초기화된 것만 노출함.
- 특정 모듈을 스프링 빈으로 등록하면 해결
- 모듈 등록 코드
```java
/* build.gradle 에*/
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-hibernate5-jakarta'
///////////////////////////////////////////
/* java */
@Bean
Hibernate5JakartaModule hibernate5Module() {
return new Hibernate5JakartaModule();
}
```
- 해결책(2) 특정 모듈로 → 강제 로딩하여 DB조회하기
- 한계점 : 성능낭비가 생긴다. 쓸모없이 모두 다 DB조회하니까.
- 해결책(3) : 직접 강제초기화 명령코드 날리기
- 한계점 : 엔티티 직접노출의 전형적 한계
- 쓸데없이 성능낭비 및 복잡한 API Json출력
- API스펙 변경 문제
- 강제초기화 명령코드
/* 직접 강제초기화 명령코드 날리기 */ @GetMapping("/api/v1/simple-orders") public List<Order> ordersV1() { List<Order> all = orderRepository.findAllByString(new OrderSearch()); for (Order order : all) { order.getMember().getName(); //Lazy 강제 초기화 order.getDelivery().getAddress(); //Lazy 강제 초기환 } return all; }
- 한계점 : 엔티티 직접노출의 전형적 한계
- 해결책(4) : EAGER조건 하기
- 한계점 : 성능낭비하고, 성능튜닝이 어렵다.
'정리 { Java 백엔드 } > (인강) JPA 프로그래밍 +스프링부트' 카테고리의 다른 글
| (JPA_활용1) _1강. 프로젝트 환경 설정 (0) | 2023.05.10 |
|---|---|
| (JPA) <7>[조회 성능 최적화] _ V2. "엔티티를 DTO로 변환" (0) | 2023.04.11 |
| (JPA) <5> API개발고급_ 조회용 샘플 데이터 입력 (0) | 2023.04.09 |
| (JPA) <3> API개발기본_회원조회API (0) | 2023.04.07 |
| <2> API개발기본_회원수정API (0) | 2023.04.06 |
댓글