객체그래프 탐색
- 객체는 객체 그래프로 연관된 객체를 탐색한다.
- Entity는 객체가 데이터베이스(RDB)와 매핑되어 있어서 자유롭개 객체를 탐색하는데 제한이 있다(필요할 때마다 쿼리를 다 날려야 하니).
- // order.getMember() → orders 테이블과 member 테이블의 정보를 모두 가져와야 하는상태
- JPA는 프록시객체라는 기술을 사용하여 연관된 객체를 처음부터 데이터베이스에서 조회하지 않고, 실제 사용하는 시점에 조회할 수 있다.
- order.getMember().getNam() 등을 호출했을 때, 해당 멤버 데이터를 join 해서 가져오는 것
프록시 객체
프록시의 특징
- 프록시 객체는 처음 사용할 때 한번만 초기화 된다.
- 프록시 객체의 초기화 : 프록시 객체는 member.getName() 처럼 실제 사용될 때 데이터베이스를 조회해서 실제 엔티티 객체를 생성하는데 이것을 프록시 객체의 초기화라 함
- 프록시 객체가 초기화되면, 프록시 객체를 통해서 실제 엔티티에 접근 할 수 있다.
- 필요할 때 그 엔티티를 가지고 와서
프록시 객체
→엔티티
로 변경
- 초기화는 영속성 컨텍스트의 도움을 받아야 가능하다. 따라서 준영속 상태의 프록시를 초기화하면 LazyInitializationException 예외가 발생한다.
프록시와 컬렉션 래퍼
- 하이버네이트는 엔티티를 영속 상태로 만들 때 엔티티에 컬렉션이 있으면 컬렉션을 추적하고 관리할 목적으로 원본 컬렉션을 하이버네이트가 제공하는 내장 컬렉션으로 변경하는데 이것을 컬렉션 래퍼라 함(PersistentBag)
- 컬렉션 래퍼도 컬렉션에 대한 프록시 역할을 함
지연로딩(LAZY) & 즉시로딩(EAGER)
지연로딩
연관된 엔티티를 실제 사용할 때 조회한다.

- member.getOrders() 로 얻어온 Order를 사용하려고 할 때, 초기화 요청이 시작됨
- 사용 전에는 실제 엔티티 객체 대신에 데이터베이스 조회를 지연할 수 있는 가짜 객체가 필요한데 이것을 프록시 객체라 함
- 프록시 객체는 실제 객체에 대한 참조(target)를 보관. 그리고 프록시 객체의 메서드 호출 시, 프록시 객체는 실제 객체의 메소드를 호출
- 엔티티를 프록시로 조회할 때 식별자(PK) 값을 파라미터로 전달하는 데 프록시 객체는 이 식별자 값을 보관함. 프록시 객체가 식별자 값을 갖고 있기에 getId() 메서드를 호출한다고 해서 엔티티가 초기화 되지는 않음
즉시로딩
엔티티를 조회할때, 연관된 엔티티를 함께 조회한다.
- EagerFetch 사용시 주의점
- 컬렉션 하나 이상 즉시 로딩 하지 않기. 카르테시안 곱 만큼의 데이터가 반환될 수 있음
EagerFetch
인 경우, JPQL 을 사용하여 연관된 엔티티를 제외하고 조회하여도, 결국 엔티티를 구성하기 위해 SQL 쿼리를 다시 실행해 연관된 엔티티를 조회하게 됨

- 위 코드에서 entityManager.clear() 를 통해 Persistence Context 가 비워짐
- findByEmail에서는 Account와 Relation관계인 Department만 가져옴
- 그러므로 then 밑에서 fetchAccount에서 organization과 room 을 조회할 시, sql이 다시 나가게 됨
- 만약 Persistence Context에 given 절에서 불러온 organization과 room이 있다면 then 절에서 sql이 다시 발생하지는 않음. Persistence Context에서 찾아서 바로 가져올 수 있기 때문에(id 기반으로)