간단한 주문 조회 v1

JIWOO YUN·2023년 9월 11일
0
post-custom-banner

지연로딩과 조회 성능 최적화

  • 핵심으로 처리하는 문제
    • 지연로딩으로 발생하는 성능 문제를 해결하자.

이 문제는 실무에서 JPA를 사용하려면 100% 으로 이해해야한다!

V1 버전 :엔티티 직접 노출하는 경우

Order 와 Member 는 ManyToOne 관계

Order 와 delivery 는 OneToOne관계

(Order와 OderItems는 OneToMany 관계 -> 이건 복잡하기 떄문에 다음 강의에서 설명)

OrderRepository에 만들어둔 findAllByString을 통해서 List로 그냥 받아서 넘겨준다.

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

    }

근데 이렇게 할 경우 postMan에서 해당 Get을 보내는 경우 무한루프에 빠지게 된다.

  • Order에 있는 Member를 통해서 Member를 조회하는데 거기서 member안에 Order가 있기 때문에 다시 Order를 조회하게 되어서 끝이 나지 않게 된다.
  • 해결법은 양방향 연관관계일 경우, 한쪽의 관계에서 @JsonIgnore를 적어서 한쪽을 무시해주는 방법으로 해결이 가능하다.

이렇게 첫번째 문제를 해결하자 이제 다음 문제가 또 발생해버렸다.

  • Type definition error 뭐시기 뭐시기하면서 오류가 발생한다.

  • Order를 가져올때 Order안에 Member가 Lazy로딩이기 때문에 Member를 가져오지 않고 Hibernate에서 가짜 프록시 멤버 객체를 생성해서 넣어준다고한다.(Proxy의 경우 JPA 기본편에서 설명해준다.)

    • 프록시 객체로 채워놓았다가 Member의 객체의 값을 직접 꺼내는 경우에만 DB에 SQL을 날려서 member객체를 채워주는 형식
  • Jackson 라이브러리는 기본적으로 프록시 객체를 json으로 어떻게 생성해야하는지 모른다.

현재는 이렇게 했지만 잊으면 안된다 -> 엔티티를 직접 노출하면 안된다는 것을.

  • 모든 과정을 처리하고 postMan에서 get을 통해 조회를 해볼 경우

현재와 같이 나오게 된다. member와 orderItems,delivery가 null 인경우는 이 3가지 객체가 Lazy 로딩인데 hibernate5Module의 기본설정이 지연로딩은 무시하고 진행되기 때문에 null로 반환 되는 것이다.

강제로 Lazy로딩을 시켜서 값을 가져올 수는 있다. hibernate5Module의 빈 값에 설정해주면되긴하지만 엔티티를 전부 노출하는건 좋은 방법이 아니기 때문에 알고만 하고 넘어가도록하자.

다른 방법으로는 주문 조회한 all 을 이와같이 for문을 돌려서 member와 delivery의 Lazy를 강제 초기화하는 방법이다.

    @GetMapping("/api/v1/sample-orders")
    public List<Order> ordersV1(){
        List<Order> all = orderRespository.findAllByString(new OrderSearch());
        for(Order order: all){
            order.getMember().getName(); //Lazy 강제 초기화
            order.getDelivery().getAddress();//Lazy 강제 초기화
        }
        return all;
    }

member와 delivery는 제대로 출력되는 모습

orderItems는 강제초기화를 하지 않았기 때문에 null로 표시되는 모습

profile
열심히하자
post-custom-banner

0개의 댓글