즉시로딩과 지연로딩의 원리를 알기 위해서는 JPA 프록시 객체에 대해서 이해하는 것이 중요하다.
User refUser = em.getReference(User.class, 1L);
System.out.println("refUser = " + refUser.getClass()); // Proxy 객체
em.detach(refUser); // 준영속 상태 만들기
refUser.getUsername(); // 프록시 초기화시 LazyInitializationException 예외 발생
프록시 객체를 통해 엔티티를 실제 사용하기 전까지 데이터 베이스 접근을 미룰 수 있다.
엔티티를 조회할 때 연관관계에 있는 엔티티를 조회하는 시점에 따라 즉시로딩과 지연로딩으로 나눌 수 있다.
Member 엔티티를 조회 시점에 Member 엔티티와 연관관계를 맺고 있는 Team 엔티티까지 데이터베이스로 부터 조회한다. 이 때 하이버네이트는 즉시 로딩을 최적화하기 위해, 두 개의 조회 쿼리를 사용하지 않고 조인 쿼리를 사용한다.
따라서 즉시로딩은 가급적 사용하지 않고 지연로딩을 사용한다.
프록시 객체를 사용하여, 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