Entity 조회
em.getReference( ) 는 JPA의 EntityManager에서 제공하는 메서드로 특정 엔티티의 프록시 객체를 반환한다.
지연 로딩(Lazy Loading)을 활용해 데이터베이스 조회를 미루고 실제로 엔티티의 속성에 접근할 때만 데이터베이스를 조회하도록 한다.
Entity 조회
위와 같은 연관관계를 가지는 Entity가 있다고 가정한다.
tutor만 조회하는 경우
Tutor findTutor = em.find(Tutor.class, 1L);
String tutorName = findTutor.getName();
System.out.println("tutorName = " + tutorName);
tutor만 조회하는 경우 Company도 함께하기 때문에 낭비가 발생한다.
이것을 프록시를 사용하여 효율적으로 관리할 수 있다.
💡 참고
em.find( ) 는 데이터베이스를 통해 실제로 저장된 Entity 를 조회한다.
em.find( ) vs em.getReference( )
em.find( )
public class Main {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("entity");
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
transaction.begin();
try {
Tutor tutor = new Tutor("wonuk");
em.persist(tutor);
// 영속성 컨텍스트 초기화
em.flush();
em.clear();
// Entity 객체 조회
Tutor findTutor = em.find(Tutor.class, tutor.getId());
transaction.commit();
} catch (Exception e) {
transaction.rollback();
} finally {
em.close();
}
emf.close();
}
}
실행 결과
tutor에 대한 조회에 left join으로 연관관계에 있는 company도 함께 조회한다.
em.getReference( )
데이터베이스에 저장된 Entity가 아닌 프록시 Entity 객체를 조회한다.
Tutor proxyTutor = em.getReference(Tutor.class, tutor.getId());
실행결과
em.find( ) 와 다르게 company에 대한 조회 SQL이 실행되지 않는다.
System.out.println("proxyTutor.getName() = " + proxyTutor.getName());
실행 결과
실제 값을 사용하는 시점에 SQL이 발생한다.
System.out.println("proxyTutor.getClass() = " + proxyTutor.getClass());
실행 결과
Hibernate가 만드는 Proxy 객체
Proxy
JPA에서 엔티티 객체의 지연 로딩(Lazy Loading)을 지원하기 위해 사용하는 대리 객체로 실제 엔티티 객체를 생성하거나 데이터베이스에서 값을 읽어오지 않고도 엔티티의 참조를 사용할 수 있다.
Proxy 객체
데이터베이스 조회를 지연하는 가짜(Proxy) 객체를 조회한다.
- 실제 Entity와 == 비교 실패, instanceof 사용해야 한다.
target 필드에 진짜 객체의 참조를 보관한다.
Proxy 객체 초기화
0. em.getReference( ) : 프록시 객체 조회
1. getName( ) : 프록시 객체의 getName( ) 호출
2. JPA가 영속성 컨텍스트에 target 초기화 요청
3. 실제 DB 조회
4. Entity 생성
5. target의 getName( ) 호출
Proxy 특징
최초로 사용(실제 Entity에 접근)할 때 한 번만 초기화된다.
프록시 객체를 통해 실제 Entity에 접근할 수 있다.
em.getReference( ) 호출 시 영속성 컨텍스트에 Entity가 존재하면 실제 Entity가 반환된다.
준영속 상태에서 프록시를 초기화하면 LazyInitializationException 예외가 발생한다.
Tutor proxyTutor = em.getReference(Tutor.class, tutor.getId());
System.out.println("proxyTutor.getClass() = " + proxyTutor.getClass());
// 준영속 상태
em.detach(proxyTutor);
proxyTutor.getName();
실행 결과
- detach( ) : 영속성 컨텍스트가 관리하지 않는다.
- 영속성 컨텍스트를 통해 도움을 받아야만 실제 Entity에 접근이 가능하다
- 실제 JPA 개발에서 가장 많이 마주치는 Exception이다.
'JPA' 카테고리의 다른 글
상속 관계 매핑 (0) | 2024.11.28 |
---|---|
N:M 연관관계 (0) | 2024.11.27 |
1:1 연관관계 (1) | 2024.11.27 |
1:N 연관관계에서 1이 연관관계 주인일 때 (0) | 2024.11.27 |