Proxy
- 엔티티를 실제 사용하는 시점에 객체를 DB에서 조회함으로써 효율을 높인다.
- 그 이전에는 프록시 객체를 생성해서 조회를 지연시킨다.
EntityManager.getReference()
- Persistence Context에 엔티티 객체가 있으면 실제 엔티티를 반환
- 엔티티 객체가 없으면 프록시 객체 반환
프록시 객체
- 실제 클래스를 상속받아서 만들어져서 겉 모양이 같고, 실제 객체 참조(target)을 보관한다.
- 사용하는 입장에서는 실제 클래스와 구분할 필요가 없다.
- 초기화: 실제 엔티티가 사용되는 시점에 Persistence Context에 실제 엔티티 생성을 요청하는 것
특징
- 프록시 객체는 처음 사용할 때 한 번만 초기화된다.
- 프록시 객체를 초기화한다고 프록시 객체가 실제 엔티티로 바뀌는 것이 아니다. 접근할 수 있게 되는 것이다.
- 프록시 객체 타입 체크 시 주의해야 한다.
- 프록시 객체를 초기화하려면 영속 상태여야 한다. 준영속 상태의 프록시를 초기화시키면 예외가 발생한다.
식별자
프록시 객체는 식별자 값을 보관한다.
@Access(AccessType.PROPERTY))
@Access(AccessType.FIELD))
getId()
: 식별자 값 외의 다른 필드를 조회하는 지 알지 못하므로 프록시를 초기화한다.
- 연관관계 설정 시 프록시를 초기화하지 않는다.
프록시 확인
PersistenceUnitUtil.isLoaded(Object entity)
: 프록시 인스턴스의 초기화 여부
entity.getClass().getName()
: 프록시 객체인지 진짜 엔티티 객체인지 여부
Eager Loading
엔티티를 조회할 때 연관된 엔티티도 함께 조회한다.
- @{연관관계}(fetch = FetchType.EAGER)
- 조인 쿼리 한 번으로 두 엔티티를 모두 조회
@ManyToOne
, @OneToOne
기본 fetch 설정값
Lazy Loading
연관된 엔티티를 실제 사용할 때 조회한다.
- @{연관관계}(fetch = FetchType.LAZY)
- 프록시를 실제 사용할 때 초기화하면서 DB를 조회
@ManyToMany
, @OneToMany
기본 fetch 설정값
💡 모든 연관관계에 Lazy Loading을 사용하고, 꼭 필요한 곳에만 Eager Loading으로 최적화하는 것이 바람직하다.