Entity 직접 노출

  • 주문, 배송 정보, 회원의 조회 API 개발한다.

  • 지연 로딩으로 발생하는 성능 문제를 단계적으로 해결한다.

무한 루프

/**
 * Order 조회
 * Order - Member는 ManyToOne
 * Order - Delivery는 OneToOne
 */
@RestController
@RequiredArgsConstructor
public class OrderSimpleApiController {
    private final OrderRepository orderRepository;

    @GetMapping("/api/v1/simple-orders")
    public List<Order> ordersV1() {
        List<Order> all = orderRepository.findAllByString(new OrderSearch());

        return all;
    }
}
  • API를 요청하면 무한 루프를 돈다.

  • Order와 Member가 서로를 참조하고 있기 때문이다.

    • Order에 Member가 있어서 들어가보면 Member에 Order가 있고...

  • jackson이 무한 루프를 돌면서 계속 객체를 만든다.

@JsonIgnore

  • 양방향이 걸리는 곳은 모두 한 쪽에 @JsonIgnore를 붙여야 피할 수 있다.

    • Order - Member

    • Delivery - Order

    • OrderItem - Order

지연 로딩 객체

  • 이번에는 bytebuddy 예외가 발생한다.

  • member는 지연 로딩으로 가져오게 되어있다.

  • DB에서 가져올 때는 order 데이터만 가져온다.

  • member에는 프록시 객체를 생성해서 넣어둔다.

    • 이때 쓰는 라이브러리가 예외에 나온 bytebuddy다.

  • jackson 라이브러리가 member를 변환하려는 순간, 프록시 객체를 json으로 어떻게 생성할지 몰라 에러를 낸 것이다.

Hibernate5Module

  • Hibernate5Module을 스프링 빈으로 등록하면 해결된다.

  • 지연 로딩 때문에 member, orderItems, delivery는 null로 출력된다.

FORCE_LAZY_LOADING

  • FORCE_LAZY_LOADING

    • 강제로 지연 로딩하면서 제대로 된 데이터가 반환된다.

    • 양방향 연관 관계를 계속 로딩하기 때문에 @JsonIgnore를 꼭 한쪽에 추가해줘야 한다.

  • 하지만 이렇게 강제로 모든 데이터를 로딩하는 옵션은 좋지 않다.

    • API 스펙 상 필요 없는 데이터까지 노출된다.

    • 추가로 데이터를 끌고 오면서 성능에도 문제가 발생한다.

직접 조회

  • get()을 통해 지연 로딩된 객체를 직접 조회하게 하면 FORCE_LAZY_LOADING 없이 불러올 수 있다.

정리

  • Entity를 API 응답 형태로 외부에 노출하면 안된다.

    • DTO로 변환해서 반환하자.

  • 지연 로딩을 피하려고 즉시 로딩을 설정하면 안된다.

    • 연관 관계가 필요없는 경우에도 항상 모든 데이터를 조회하면서 성능 문제가 발생한다.

      • 연관된 데이터를 다 조회하면서 N+1 문제가 터진다.

    • 즉시 로딩으로 설정하면 성능 튜닝이 매우 어려워진다.

    • 항상 지연 로딩을 기본으로 하자.

    • 성능 최적화가 필요하면 fetch join을 사용하자.

Last updated

Was this helpful?