@ManyToOne의 fetch 속성은 JPA에서 다대일 관계를 설정할 때, 연관된 엔티티를 언제 로드할지를 결정하는 중요한 설정이다.
FetchType.EAGER: 즉시 로딩
FetchType.LAZY: 지연 로딩
FetchType.EAGER(즉시 로딩)
@ManyToOne(fetch = FetchType.EAGER)
private Building building;
특징:
- 즉시 로딩은 연관된 엔티티를 항상 즉시 함께 조회한다.
- 부모 엔티티가 로드될 때, 연관된 자식 엔티티도 즉시 조회된다.
- 한 번의 쿼리로 해결되지 않으면 N+1 문제가 발생할 수 있다.
- 예: 부모 엔티티를 조회하는 쿼리 1개 + 자식 엔티티를 각각 로드하는 쿼리가 N개 더 실행
예시:
SELECT * FROM detection WHERE id = 1;
SELECT * FROM building WHERE id = 10;
사용 상황:
- 연관된 엔티티가 반드시 사용될 것이 확실한 경우.
- 객체 탐색이 자주 일어나는 상황(예: 로딩을 기다리지 않고 즉시 필요할 때).
단점:
- 불필요한 데이터를 미리 로드할 수 있어 성능에 영향을 미칠 수 있다.
FetchType.LAZY (지연 로딩)
@ManyToOne(fetch = FetchType.LAZY)
private Building building;
특징:
- 지연 로딩은 연관된 엔티티를 필요한 시점에만 로드한다,
- 부모 엔티티가 로드될 때는 프록시 객체를 사용해 연관된 엔티티의 로딩을 지연시킨다.
- 연관된 엔티티에 접근할 때 데이터베이스 쿼리가 실행된다.
예시:
Detection detection = detectionRepository.findById(1L).get();
Building building = detection.getBuilding();
SELECT * FROM detection WHERE id = 1;
SELECT * FROM building WHERE id = 10;
사용 상황:
- 연관된 엔티티를 매번 사용하지 않을 때.
- 성능 최적화가 필요한 경우, 필요할 때만 데이터를 가져오기 위해 사용한다.
단점:
- 지연된 시점에 쿼리가 실행되기 때문에 의도치 않게 N+1 문제가 발생할 수 있다.
- 프록시 객체로 인해 LazyInitializationException이 발생할 수 있다. (트랜잭션 범위 밖에서 접근할 때)
정리: 언제 EAGER와 LAZY를 사용할까?
- FetchType.EAGER: 연관된 엔티티를 즉시 사용해야 하거나, 연관 데이터가 항상 필요할 때 사용한다.
- FetchType.LAZY: 성능 최적화가 필요하고, 연관 데이터가 항상 사용하지 않을 경우 사용한다.
Tip. 실무에서는 기본적으로 LAZY를 사용하고, 필요한 경우에만 EAGER을 사용하는 것이 좋다고 한다.