Spring/JPA

JPA 프록시 (즉시로딩, 지연로딩)

묠니르묘묘 2022. 3. 29. 21:26

Member를 조회할 때 Team도 함께 조회해야 할까?

만약 Member와 Team이 연관관계로 맺어져있다.

이 때, Member를 조회하면 JPA는 Team까지 조회하게 된다.

 

위 코드처럼 member와 team을 함께 출력하거나 사용하는 메서드가 있을때는 전부 조회하는 것이 좋다.

하지만 member만 사용하는 메서드라면 굳이 team까지 조회해야 할까?

이것은 불필요한 성능을 사용하게 되는 것이다.

 


지연로딩 LAZY 사용해서 프록시로 조회

그렇다면 불필요한 성능을 피하기위해서 전부 조회하지않으려면 어떻게 해야할까?

바로 지연로딩 LAZY를 사용하는 것이다!

 

Member 클래스

Member와 Team이 다대일 관계로 맺어져있는데 이때 FetchType.LAZY 를 사용하는 것이다.

Member와 Team 조회

위 사진처럼 동작을 수행한다고 했을때 생각해보자.

  1. 예시로 사용할 Member와 Team 객체를 DB에 저장해놓는다.
  2. 영속성 컨텍스트를 비워서 처음 시작한 초기상태로 만든다. (em = EntityManager, tx = em.getTransaction())
  3. Member를 조회한다. 이 때 조회한 Member의 Team 객체는 무슨 타입인지 확인한다.
  4. 조회한 Member의 Team을 검색하여 초기화한다.

FetchType.LAZY

위 사진처럼 3번 때는 처음 member1을 조회하고나면 지연로딩으로 프록시 team1 객체(가짜)가 만들어진다.

이 때 타입은 m = class hellojpa.Team$HibernateProxy$NZRZoIGu 이런식으로 프록시 객체타입이라고 나오게 된다.

4번 동작을 실행하는 순간 프록시 team1 객체가 진짜 Team객체를 상속받게 된다.

즉, DB를 실제로 조회하게되고 실제 team1 정보를 가지게 된다.

하지만 현재 객체타입인 프록시가 바뀌는 것은 절대 아니다!

프록시 객체가 DB를 조회한 team1 객체를 상속받아서 값을 전부 가지고 있는 것이다!

 


즉시로딩 EAGER 으로 한 번에 조회

지연 로딩과 달리 즉시 로딩은 Member를 조회할 때 Team까지 한 번에 조회하게 된다.

 

FetchType.EAGER

즉, 지연 로딩에서 설명한 동작방식의 3번에서 team1까지 조회하게 된 것이다.

그러므로 team1은 프록시타입의 가짜객체가 아닌, Team 타입의 객체가 만들어진다.

 


실무에서는 무엇을 쓰는게 좋을까?

왠만하면 즉시로딩 보다는 지연로딩으로 하는것이 여러 문제점을 예방할 수 있다.

 

  • 즉시 로딩은 JPQL에서 N+1 문제가 발생할 수 있다.
  • N+1 : 1개의 최초 쿼리가 발생했는데, 그것 때문에 추가쿼리 N개가 발생한다고 해서 N+1 이라고한다

       (N+1 : 1개의 최초 쿼리가 발생했는데, 이것 때문에 추가 쿼리 N개가 발생한다고 해서 N+1)

  • 즉시 로딩을 적용하면 예상치 못한 SQL 발생
  • @ManyToOne, @OneToOne은 기본이 즉시 로딩
  • @ManyToMany, OneToMany는 기본이 지연 로딩

 

 


자바 ORM 표준 JPA 프로그래밍 / 김영한 지음 / 에이콘출판주식회사 출판

자바 ORM 표준 JPA 프로그래밍 - 기본편 / 김영한 / 인프런 강의