(3) 지연로딩 활용
8.3.1 프록시와 컬렉션 래퍼
하이버네이트는 엔티티를 영속 상태로 만들 때 엔티티에 컬렉션이 있으면 컬렉션을 추적하고 관리할 목적으로 원본 컬렉션을 하이버네이트가 제공하는 내장 컬렉션으로 변경하는데, 이를 컬렉션 래퍼 라고 한다.
이러한 컬렉션 래퍼가 컬렉션에 대해 지연 로딩을 처리해준다.
참고로 member.getOrders()
를 호출해도 컬렉션은 초기화되지 않는다.
`member.getOrders().get(0)' 처럼 컬렉션에서 실제 데이터를 조회할 때 데이터베이스를 조회해서 초기화하기 때문이다.
내장 컬렉션 : org.hibernate.collection.internal.PersistentBag
8.3.2 JPA 기본 페치 전략
fetch 속성의 기본 설정값
- @ManyToOne, @OneToOne : 즉시 로딩(FetchType.EAGER)
- @OneToMany, @ManyToMany : 지연 로딩(FetchType.LAZY
연관된 엔티티가 하나면 즉시 로딩
, 컬렉션이면 지연 로딩
을 사용한다.
컬렉션을 로딩하는 것은 비용이 많이 들고 잘못하면 너무 많은 데이터를 로딩할 수 있기 때문이다.
모든 연관관계에 지연 로딩을 사용하는 것을 추천한다.
그리고 애플리케이션 개발이 어느 정도 완료단계에 왔을 때 실제 사용하는 상황을 보고 꼭 필요한 곳에만 즉시 로딩을 사용하도록 최적화하면 된다.
SQL을 직접 사용하면 이런 유연한 최적화가 어렵다. ex) SQL로 각각의 테이블 조회해서 처리하다가 조인으로 한 번에 조회하도록 변경하려면 많은 SQL과 애플리케이션 코드 수정..
컬렉션에 FetchType.EAGER 사용 시 주의점
컬렉션을 하나 이상 즉시 로딩하는 것은 권장하지 않는다.
컬렉션과 조인한다는 것은 데이터베이스 테이블로 보면 일대다 조인이다.
일대다 조인은 결과 데이터가 다 쪽에 있는 수만큼 증가하게 된다.
서로 다른 컬렉션을 2개 이상(예를 들어 N, M 테이블) 조인하면 SQL 실행 결과가 N * M 이 되면서 너무 많은 데이터를 반환하여 애플리케이션 성능 저하
컬렉션 즉시 로딩은 항상 외부 조인을 사용한다.
예를 들어, 회원과 팀은 다대일 관계.
이 둘을 조인할 때 회원 테이블의 외래 키에
not null
제약조건을 걸어두면 모든 회원은 팀에 소속되므로 항상 내부 조인 사용 가능하지만 팀에서 회원으로 일대다 관계 조인 시 회원이 한 명도 없는 팀을 내부 조인하면 팀까지 조회되지 않는다.
@ManyToOne, @OneToOne
(optional = false) : 내부 조인
(optional = true) : 외부 조인
@OneToMany, @ManyToMany
(optional = false) : 외부 조인
(optional = true) : 내부 조인