위 엔티티에서 Member 테이블 내에 username만 조회한다고 가정할 때, 과연 Team과 함께 조회할 필요가 있을까 라는 질문으로부터, 즉시로딩과 지연로딩의 개념이 시작된다.
즉시로딩과 지연로딩의 원리를 알기 위해서는 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