프록시와 연관관계
프록시 객체는 실제 객체의 참조 대상(target)를 보관한다. 프록시 객체를 호출하면 프록시 객체는 실제 엔티티 객체를 호출한다. 사용하는 입장에서는 진짜 객체인지 프록시 객체인지 구분하지 않고 사용하면 된다.
em.find() => 데이터베이스를 통해 실제 엔티티 객체 조회
em.getReference() => 프록시 객체를 통해 엔티티 객체 조회
프록시 객체의 초기화
- 프록시 객체는 처음 사용할때 한번만 초기화한다.
- 프록시 객체는 초기화 할때 프록시 객체가 실제 엔티티로 바뀌는것이 아니다. 초기화를 하면 프록시 객체를 통해 실제 엔티티에 접근이 가능하다.
- 프록시 객체는 실제 엔티티를 상속한다. 실제 엔티티는 아니기 때문에 타입 체크할대 주의해야한다. (== 말고, instance of 사용)
- 만약 영속성 컨택스트에 해당 엔티티가 있으면 em.getReference() 를 호출해도 실제 엔티티를 반환한다. (프록시 객체가아닌 실제 엔티티를 가져옴)
- 준영속 상태일때 프록시를 초기화하면 예외가 발생한다. (하이버네이트 org.hibernate.LazyInitializationException 예외)
지연 로딩 Lazy Loading
지연 로딩은 객체가 필요한 시점까지 객체 초기화를 연기하기 위해 컴퓨터 프로그래밍에서 일반적으로 사용되는 디자인 패턴이다. fetch 타입을 LAZY로 설정하면 된다. ( @ManyToOne(fetch = “FetchType.LAZY”) )
예를 들어 Member를 조회할때 Lazy 로딩 설정이 되어있는 Team 엔티티는 프록시 객체로 가져온다. Team엔티티는 프록시 객체로 생성이되고 해당 엔티티를 사용하는 시점에 데이터베이스에 쿼리가 나간다.
즉시 로딩 Eager Loading
JPA 구현체는 가능하면 조인을 사용해서 SQL 한번에 함께 조회한다.
즉시 로딩은 엔티티를 조회할때 연관된 객체를 조인해서 한번에 조회해 온다. fetch 타입을 EAGER로 설정하면 된다.
예를 들어 Member를 조회할때 Team엔티티도 조인해서 한번에 가져온다. 이때 Team엔티티는 지연로딩과 다르게 실제 엔티티 객체이다.
즉시 로딩 주의사항
- 가급적이면 지연 로딩만 사용해야 한다.
- 즉시 로딩을 적용하면 예상하지 못한 SQL이 발생해 문제를 야기 시킬 수 있다.
- 즉시 로딩은 N+1 문제를 일으킨다. (Team만 조회하려 하는데 연관된 Member를 모두 조회를 함)
- @ManyToOne, @OneToOne 은기본이 즉시 로딩이다. 설정할때 LAZY로 설정을 꼭 해줘야한다.
즉시 로딩을 사용하지 않고 JPQL fetch 조인 또는 엔티티 그래프 기능을 사용하는것이 좋다.