지연 로딩과 조회 성능 최적화 - 엔티티 직접 노출

HotFried·2023년 11월 23일
0

이전 내용
1. API 호출 시 FetchType.Lazy -> 무한루프

2. API 호출 시 FetchType.Lazy -> Json 오류 (InvalidDefinitionException - ByteBuddyInterceptor)


API호출 시 무한루프와 InvalidDefinitionException을 해결했다.
이 때 결과를 출력하게 되면

[
    {
        "id": 4,
        "member": null,
        "orderItems": null,
        "delivery": null,
        "orderDate": "2023-11-23T16:57:32.353821",
        "status": "ORDER",
        "totalPrice": 50000
    },
    {
        "id": 11,
        "member": null,
        "orderItems": null,
        "delivery": null,
        "orderDate": "2023-11-23T16:57:32.394409",
        "status": "ORDER",
        "totalPrice": 220000
    }
]

프록시 객체의 경우 null이 반환된다.


ForceLazyLoading

Hibernate5Module을 빈으로 등록할 때

@Bean
    Hibernate5Module hibernate5Module() {
        Hibernate5Module hibernate5Module = new Hibernate5Module();
        hibernate5Module.configure(Hibernate5Module.Feature.FORCE_LAZY_LOADING, true);
        return hibernate5Module;
    }

위와 같이 FORCE_LAZY_LOADING 옵션을 키게 되면, null이 반환되지 않고 강제로 지연로딩을 실행하기 때문에 모든 값이 반환된다.

그렇기에, 지나치게 많은 쿼리가 나가기 때문에 매우 성능이 좋지 않다.


대안으로, API에 반복문을 이용해 직접 조회하는 방법도 있다.

  • get()을 통해 지연 로딩된 객체를 직접 조회하게 하면 FORCE_LAZY_LOADING 없이 불러올 수 있다.
@GetMapping("/api/v1/simple-orders")
    public List<Order> ordersV1() {
        List<Order> all = orderRepository.findAll(new OrderSearch());

        for (Order order : all) {
            order.getMember().getName();
            order.getDelivery().getOrder();
        }

        return all;
    }

정리

  • Entity를 API 응답 형태로 외부에 노출하면 안된다.
    (DTO로 변환해서 반환)
  • 지연 로딩을 피하려고 즉시 로딩을 설정하면 안된다.
    • 연관 관계가 필요없는 경우에도 항상 모든 데이터를 조회하면서 성능 문제가 발생한다.
      • 연관된 데이터를 다 조회하면서 N+1 문제가 터진다.
    • 즉시 로딩으로 설정하면 성능 튜닝이 매우 어려워진다.
    • 항상 지연 로딩을 기본으로 하되, 성능 최적화가 필요하면 fetch join을 사용하자.

결국 이 모든 문제는 Entity를 외부에 노출해서 발생하는 문제이다.

매우 중요

반드시, Entity대신 DTO를 매핑해서 해당 문제가 발생하지 않도록 한다.


참고 :

실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화

profile
꾸준하게

0개의 댓글