사전 준비 - 조회용 샘플 데이터 입력
jpabook::jpashop::InitDb
Code Content
Tips
•
IntelliJ shortcut
◦
cmd + opt + m : duplicate code refactor(중복된 코드들을 하나의 메서드로 추출해준다.)
◦
cmd + opt + v : method 반환 값에 따라 변수 선언을 해준다.
간단한 주문 조회 V1: 엔티티 직접 노출
Code Content
•
우선 엔티티를 직접 노출(반환) 하는것은 좋지 않다.(저번 챕터에서도 언급)
•
해당 API를 호출하면 Order
Member와 Order
Delivery간에 서로의 엔티티를 조회하는것이 무한순회를 하게되어 에러가 발생하고 제대로된 Response가 오지 못한다.
Order
Delivery 간 무한참조 결과
@JsonIgnore
양방향 연관관계부분에 @JsonIgnore Annotation을 추가해주면 무한 루프 에러는 해결된다. 하지만, 다음 에러가 발생하는데 보도록 하자.
•
ByteBuddyInterceptor에서 Type defnition error가 발생한것을 볼 수 있다. 어째서 해당 에러가 났을까?
→ 현재 코드의 로딩 전략은 지연로딩(LAZY)전략을 사용한다. 그 말은 Member, Delivery등의 엔티티들을 조회하는 시점에서는 실제 객체가 아닌 프록시 객체를 가지고 있다. 그렇기 때문에 jackson 라이브러리는 기본적으로 이 프록시 객체를 json으로 어떻게 생성해야 하는지 모르기 때문에 예외가 발생하는 것이다.
•
해결책
→ Hibernate5Module 을 스프링 Bean으로 등록하면 해결된다.
/*build.gradle*/
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-hibernate5'
/*JpashopApplication.java*/
@Bean
Hibernate5Module hibernate5Module(){
return new Hibernate5Module();
}
Java
복사
◦
gradle에 implentation 할 때 version을 따로 입력해주지 않으면 Gradle에서 자동으로 현재 버전과 잘 맞는 버전을 import해서 관리해준다.
◦
아래와 같이 hibernate5Module설정을 통해 강제로 지연 로딩도 사용 가능하다
Code Content
•
(Important) 계속 언급했지만 엔티티를 API에 직접 노출하는 것은 좋지 않다. 그래서 Hibernate5Module을 이용하는 방법은 알아만 두고 실무에서는
DTO로 변환해서 반환하는것이 더 좋은 방법이다.
주의점: 지연로딩(LAZY)의 문제를 피하기 위해 즉시 로딩(EAGER)으로 설정하는 것은 안된다. 즉시 로딩 때문에 연관관계가 필요 없는 경우에도 데이터를 조회하기 때문에 성능 문제가 발생할 수 있다.
지연로딩을 기본으로 하고 필요하다면 페치 조인(fetch join)을 이용하자.
간단한 주문 조회 V2: 엔티티를 DTO로 변환
Code Content
V2버전으로 API호출했을 때 실행되는 쿼리
Code Content
•
쿼리가 1 + N + N 번 실행된 것을 볼 수 있다.
→ 물론, 여기서 member가 동일할 경우 처음 조회 이후 다시 조회 하지 않기 때문에 1번의 쿼리수행이 더 줄어들 수 있지만, 흔한 케이스가 아니기에 고려하지 않는다.
•
Order 조회가 많아질수록 기하급수적으로 쿼리수행이 많아지고 성능저하가 일어날 수 있다.
간단한 주문 조회 V3: 엔티티 DTO로 변환 → 페치 조인 최적화
Code Content
간단한 주문 조회 V4: JPA에서 DTO로 바로 조회
Code Content::Controller
Code Content::OrderSimpleQueryRepository 조회 전용 리포지토리
Code Content::OrderSimpleQueryDto
정리
→엔티티를 DTO로 변환하거나, DTO로 바로 조회하는 두가지 방법은 각각 장단점이 있다. 둘 중 상황에 따라서 더 나은 방법을 선택하면 된다.
엔티티로 조회하면 리포지토리 재사용성도 좋고, 개발도 단순해진다. 따라서 권장하는 방법은 다음과 같다.
쿼리 방식 선택 권장 순서
1.
우선 엔티티를 DTO로 변환하는 방법을 선택한다.
2.
필요하면 fetch join으로 성능을 최적화 한다. → 대부분의 성능 이슈 해결
3.
그래도 안되면 DTO로 직접 조회하는 방법을 사용한다.
4.
최후의 방법으로 JPA가 제공하는 Native SQL이나 스프링 JDBC Template을 사용해서 SQL을 직접 사용한다.