즉시 로딩은 엔티티가 조회될 때 연관된 엔티티를 즉시 함께 로딩하는 방식입니다.
데이터베이스에서 한 번의 쿼리를 실행하거나, 연관 엔티티를 추가적으로 조회하는 쿼리를 실행하여 연관 데이터를 가져옵니다.
@Entity
public class Order {
@Id
@GeneratedValue
private Long id;
@ManyToOne(fetch = FetchType.EAGER) // 즉시 로딩 설정
private Customer customer; // 연관 엔티티
}
SELECT * FROM order o
JOIN customer c ON o.customer_id = c.id; -- 연관된 고객 데이터를 즉시 로딩
지연 로딩은 엔티티를 실제로 사용할 때 연관된 데이터를 가져오는 방식입니다.
프록시 객체를 사용하여 필요한 시점에 데이터베이스에서 추가 쿼리를 실행합니다.
@Entity
public class Order {
@Id
@GeneratedValue
private Long id;
@ManyToOne(fetch = FetchType.LAZY) // 지연 로딩 설정
private Customer customer; // 연관 엔티티
}
-- Order 조회 시
SELECT * FROM order;
-- Customer가 실제로 사용될 때 추가 쿼리 실행
SELECT * FROM customer WHERE id = ?;
| 구분 | 즉시 로딩 (Eager Loading) | 지연 로딩 (Lazy Loading) |
|---|---|---|
| 특징 | 연관 엔티티를 즉시 로드 | 실제로 사용할 때 데이터 로드 |
| 장점 | 연관 데이터의 즉시 접근 가능 | 초기 로딩 속도 빠르고 불필요한 로딩 방지 가능 |
| 단점 | 불필요한 데이터 로드 가능성, N+1 문제 발생 가능 | LazyInitializationException 위험 |
| 사용 시점 | 연관 데이터가 항상 필요할 경우 사용 | 연관 데이터가 선택적으로 필요할 경우 사용 |
즉시 로딩을 사용하면, 주 쿼리 1번 + 연관 엔티티를 가져오는 추가 쿼리 N번이 실행될 수 있습니다.
List<Order> orders = orderRepository.findAll(); // 즉시 로딩
for (Order order : orders) {
System.out.println(order.getCustomer().getName());
}
SELECT * FROM orders; SELECT * FROM customer WHERE id = ?;즉시 로딩
지연 로딩
@Query("SELECT o FROM Order o JOIN FETCH o.customer WHERE o.id = :id")
Order findOrderWithCustomer(@Param("id") Long id);
즉시 로딩과 지연 로딩은 JPA의 강력한 기능이지만 사용에 따른 트레이드오프를 잘 이해해야 합니다.
N+1 문제와 LazyInitializationException은 성능 최적화를 위해 반드시 고려해야 할 사항입니다.
프로젝트 상황에 맞게 로딩 전략을 선택하며, 필요 시 Fetch Join 등을 활용하여 효율적인 데이터 처리를 설계하는 것이 중요함을 느꼈습니다.