Spring Boot & JPA
인프런 JPA API 개발 성능 최적화 강좌 학습 및 정리한 내용 입니다.
지연로딩으로 설정된 엔티티를 API 응답으로 내려줄 때, Jackson이 데이터를 변환하다가 아래와 같은 에러가 발생한다. Order -> Member, Order -> Address 지연 로딩 (Lazy
Loading) 으로 실제 엔티티 대신 proxy 존재 함.
com.fasterxml.jackson.databind.exc.InvalidDefinitionException:
No serializer found for class org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor and no properties discovered to create BeanSerializer(to avoid exception,disable SerializationFeature.FAIL_ON_EMPTY_BEANS)(through reference chain:java.util.ArrayList[0]->com.hyeonah.hellojpa.domain.Order["member"]->com.hyeonah.hellojpa.domain.Member$HibernateProxy$RVgm0EHQ["hibernateLazyInitializer"])
Hibernate5Module 을 Spring Bean 으로 등록하면 해결 가능하다.
build.gradle jackson-datatype-hibernate5 dependency 추가
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-hibernate5'
Bean 등록
@Bean
Hibernate5Module hibernate5Module(){
final Hibernate5Module hibernate5Module=new Hibernate5Module();
// json 생성 시점에 강제로 지연로딩 해서 엔티티 정보를 가져오게 설정
hibernate5Module.configure(Hibernate5Module.Feature.FORCE_LAZY_LOADING,true);
return hibernate5Module;
}
엔티티를 직접 노출할 때 xToOne (OneToOne, ManyToOne) 양방향 연관관계에서 무한 루프에 빠지는 문제가 발생한다.
양방향 연관관계에서 한 곳에서 @JsonIgnore 설정으 관계를 끊어주어야 한다.
@JsonIgnore
@OneToMany(mappedBy = "member")
private final List<Order> orders = new ArrayList<>();
but, 엔티티를 API 응답으로 외부에 노출하는 것은 좋지 않다.API 스펙과 상관없는 데이터 노출 가능성
, API 스펙 추가 노출문제
, 성능 상 문제
등 발생한다. 그렇기 때문에 Hibernate5Module
를 사용하는 것보다는 DTO 로 변환해서 반환하는
것이 좋다.
🔑 중요
따라서, 각 API Spec에 따라 별도의 DTO로 변환하여 반환
한다.
지연 로딩 (Lazy loading) 을 피하기 위해서 즉시 로딩 (Eager)로 설정하게 되면?
지연 로딩
을 기본으로 하고, 성능 최적화가 필요한 경우에는 페치 조인(fetch join)을 사용한다. (V3)N + 1 문제: 쿼리가 총 1 + N
컬렉션 조회 최적화