즉시로딩 말고 지연로딩을 사용하자

MinSeong Kang·2022년 8월 16일
0

spring

목록 보기
13/18
위 엔티티에서 Member 테이블 내에 username만 조회한다고 가정할 때, 과연 Team과 함께 조회할 필요가 있을까 라는 질문으로부터, 즉시로딩과 지연로딩의 개념이 시작된다.

프록시

즉시로딩과 지연로딩의 원리를 알기 위해서는 JPA 프록시 객체에 대해서 이해하는 것이 중요하다.

em.find() vs em.getReference()

  • em.find()는 영속성 컨텍스트 내에 찾는 엔티티가 존재하지 않다면 즉시 데이트베이스를 통해서 실제 엔티티 객체를 조회한다.
  • 하지만 em.getReference()를 통해 데이터베이스 조회를 미루는 프록시 엔티티 객체를 조회할 수 있다. 이는 em.getReference() 호출시 쿼리가 나가지 않고, 실제 엔티티 객체를 사용하는 시점에 쿼리를 날린다.
  • 영속성 컨텍스트를 통해 실제 엔티티를 사용하는 시점에 실제 객체를 데이터베이스 조회를 통해 생성하는 것을 프록시 객체의 초기화 라고한다.

프록시 객체의 특징

  • 하이버네이트가 실제 엔티티를 상속해서 만들며, 실제 엔티티와 겉모양은 동일하다.
  • 실제 엔티티 객체를 참조(target)을 보관한다.
  • 프록시 객체는 처음 사용할 때 한번만 초기화된다.
  • 프록시 초기화시 프록시 객체가 실제 엔티티로 바뀌는 것이 아니고, 프록시 객체를 통해 실제 엔티티로 접근할 수 있다.
  • 프록시 초기화는 영속성 컨텍스트를 통해 이루어지기 때문에 만일 엔티티 객체가 준영속 상태에서 프록시 초기화시 예외가 발생한다.
User refUser = em.getReference(User.class, 1L);
System.out.println("refUser = " + refUser.getClass()); // Proxy 객체
em.detach(refUser); // 준영속 상태 만들기
refUser.getUsername(); // 프록시 초기화시 LazyInitializationException 예외 발생

프록시 객체를 통해 엔티티를 실제 사용하기 전까지 데이터 베이스 접근을 미룰 수 있다.

즉시로딩과 지연로딩

엔티티를 조회할 때 연관관계에 있는 엔티티를 조회하는 시점에 따라 즉시로딩과 지연로딩으로 나눌 수 있다.

즉시 로딩 (EAGER)

Member 엔티티를 조회 시점에 Member 엔티티와 연관관계를 맺고 있는 Team 엔티티까지 데이터베이스로 부터 조회한다. 이 때 하이버네이트는 즉시 로딩을 최적화하기 위해, 두 개의 조회 쿼리를 사용하지 않고 조인 쿼리를 사용한다.

즉시 로딩의 문제

  • 즉시 로딩을 사용하면 예상치 못한 쿼리가 발생할 수 있다. 위 예시 같은 경우는 Member 엔티티에 연관관계로 맺어 있는 엔티티가 하나이기 때문에 조인 쿼리가 단순하겠지만, 연관관계를 맺는 엔티티가 10개라면 Member 엔티티를 조회할 때 마다 10개의 테이블이 조인된 거대 쿼리가 나갈 것이다.
  • N+1 문제 가 발생한다. 최초 한번의 쿼리로 인해 N개 만큼의 추가 쿼리가 발생한다.

따라서 즉시로딩은 가급적 사용하지 않고 지연로딩을 사용한다.

지연로딩 (LAZY)

프록시 객체를 사용하여, Member 엔티티를 조회했을 때 Team 엔티티는 데이터베이스에서 조회하지 않고 프록시 형태로 생성한다. 연관관계와 맺어있는 엔티티(Team)을 실제 사용하는 시점에 프록시 객체 초기화가 진행되며, 데이터베이스를 통해 Team 엔티티 조회가 이루어진다.

지연로딩 사용하기

@OneToMany와 @ManyToMany는 기본적으로 지연로딩을 지원하기 때문에 따로 설정할 필요가 없지만, @ManyToOne과 @OneToOne의 경우 기본 설정이 즉시로딩으로 되어 있어 지연로딩으로 설정해야 한다.

@ManyToOne(fetch = FetchType.LAZY)
@OneToOne(fetch = FetchType.LAZY)

결론!! 모든 연관관계는 모두 지연로딩을 사용하고 필요한 곳에만 즉시 로딩을 사용한다!!

참고자료

https://www.inflearn.com/course/ORM-JPA-Basic/dashboard
https://gist.github.com/taekwon-dev/008a02157948a2fe16e29c90fa3e4bce

0개의 댓글