<aside>
1️⃣ 엔티티의 연관관계란?
</aside>
- 연관관계는 엔티티 간의 관계를 의미하며, 객체지향 모델에서의 관계를 데이터베이스 모델에 매핑하는 작업이다. JPA는 다음과 같은 다양한 연관관계를 지원한다.
- 일대다 (One-to-Many) 관계:
- 하나의 엔티티가 다른 엔티티들과 여러 개의 관계를 맺을 수 있는 관계이다. 예를 들어, 하나의 주문(Order)은 여러 개의 주문 상품(OrderItem)을 가질 수 있다.
- 다대일 (Many-to-One) 관계:
- 여러 개의 엔티티가 하나의 엔티티와 관계를 맺을 수 있는 관계이다. 예를 들어, 여러 개의 주문 상품(OrderItem)은 하나의 주문(Order)에 속할 수 있다.
- 일대일 (One-to-One) 관계:
- 하나의 엔티티가 다른 엔티티와 정확히 하나의 관계를 맺는 관계이다. 예를 들어, 회원(Member)은 하나의 프로필(Profile)을 가질 수 있다.
- 다대다 (Many-to-Many) 관계:
- 여러 개의 엔티티가 다른 여러 개의 엔티티와 서로 다수의 관계를 맺을 수 있는 관계이다. 예를 들어, 하나의 주문(Order)은 여러 개의 상품(Product)을 가질 수 있고, 한 상품(Product)은 여러 개의 주문(Order)에 속할 수 있다.
- 연관관계는 주로 어노테이션을 사용하여 표현하며, JPA에서는 다양한 어노테이션을 제공한다. 예를 들어,
@ManyToOne
, @OneToMany
, @OneToOne
, @ManyToMany
등의 어노테이션을 사용하여 연관관계를 표현할 수 있다.
- 연관관계를 매핑할 때는 주인(owner)과 종속(non-owner) 개념을 고려해야 한다.
주인은 실제 데이터베이스 테이블에서 외래 키를 관리하고, 종속은 주인의 설정에 따라 외래 키를 사용한다. 양방향 연관관계를 설정할 때는 양쪽 엔티티에 각각 필드와 매핑 설정을 해야 한다.
<aside>
2️⃣ 지연 로딩(Lazy Loading)과 즉시 로딩(Eager Loading)
</aside>
- 지연 로딩(Lazy Loading)과 즉시 로딩(Eager Loading)은 JPA에서 연관된 엔티티를 로딩하는 방식을 나타내는 로딩 전략이다. 두 가지 전략은 각각 특징과 장단점을 가지고 있다. 이제 각각의 로딩 전략에 대해 자세히 설명하겠다.
- 지연 로딩(Lazy Loading):
- 지연 로딩은 연관된 엔티티를 실제로 사용할 때 로딩하는 전략이다.
- 연관된 엔티티를 조회하는 시점에서 해당 엔티티의 데이터가 필요한 경우에만 데이터베이스에서 조회된다.
- 엔티티를 로딩할 때 프록시(Proxy) 객체가 생성되어 실제 데이터가 필요한 시점에서 데이터베이스에서 조회된다.
- 지연 로딩은 연관된 엔티티가 많고, 연관된 엔티티가 필요하지 않은 경우 성능상의 이점을 가져올 수 있다.
@ManyToOne
, @OneToOne
등의 연관관계 필드에 **fetch = FetchType.LAZY
**로 설정하여 지연 로딩을 사용할 수 있다.
- 즉시 로딩(Eager Loading):
- 즉시 로딩은 연관된 엔티티를 함께 조회하는 전략이다.
- 연관된 엔티티가 필요한 시점보다 미리 로딩되므로, 데이터베이스에서 한 번의 쿼리로 모든 연관 엔티티를 조회한다.
- 즉시 로딩은 연관된 엔티티가 적거나 대부분의 경우에 필요한 경우에 사용된다.
@ManyToOne
, @OneToOne
등의 연관관계 필드에 **fetch = FetchType.EAGER
**로 설정하여 즉시 로딩을 사용할 수 있다.
- 각 로딩 전략에는 장단점이 있으므로 상황에 따라 적절한 전략을 선택해야 한다.
지연 로딩은 필요한 시점에 데이터를 로딩하여 성능을 향상시킬 수 있지만, 지속적인 데이터베이스 액세스가 필요한 상황에서는 성능 저하의 원인이 될 수 있다.
즉시 로딩은 데이터를 한 번에 로딩하여 응답 시간을 단축시킬 수 있지만, 불필요한 데이터 로딩으로 인해 메모리 낭비가 발생할 수 있다.
- 로딩 전략은 어노테이션을 사용하여 설정할 수 있으며, 기본값은 일대다, 다대다의 컬렉션 연관관계는 지연 로딩으로 설정되고, 다대일, 일대일의 단일 연관관계는 즉시 로딩으로 설정된다.
따라서, 필요에 따라 명시적으로 로딩 전략을 설정할 수 있다.
<aside>
3️⃣ 지연 로딩을 사용하는게 좋은 이유
</aside>
- 성능 최적화:
- 지연 로딩은 실제로 필요한 시점에 데이터를 로딩하기 때문에, 불필요한 데이터 로딩을 방지하여 성능을 최적화할 수 있다. 즉시 로딩은 연관된 모든 엔티티를 조회할 때 함께 로딩되므로, 데이터 규모가 크고 복잡한 연관관계에서는 불필요한 데이터를 로딩하여 성능 저하를 초래할 수 있다.
- 네트워크 부하 감소:
- 지연 로딩은 연관된 엔티티를 실제로 사용할 때 로딩되므로, 필요한 데이터만 조회하여 네트워크 부하를 감소시킬 수 있다. 즉시 로딩은 모든 연관 엔티티를 함께 로딩하므로 필요하지 않은 데이터까지 조회되어 데이터 전송량이 증가할 수 있다.
- 데이터 일관성:
- 지연 로딩은 연관된 엔티티를 필요한 시점에 조회하기 때문에, 연관 엔티티의 상태 변화에 유연하게 대응할 수 있다. 즉시 로딩은 연관 엔티티를 미리 로딩하므로, 연관 엔티티의 상태 변화에 대한 데이터 일관성을 유지하기 어려울 수 있다.
- 복잡한 객체 그래프 처리:
- 객체 그래프에 깊은 연관관계가 있는 경우, 지연 로딩을 사용하면 필요한 부분만 로딩하여 복잡한 객체 그래프를 효과적으로 처리할 수 있다. 즉시 로딩은 모든 연관 엔티티를 함께 로딩하므로, 객체 그래프의 깊이가 깊을수록 데이터베이스 액세스 및 메모리 사용량이 증가하여 처리가 복잡해질 수 있다.
- 캐시 효율성:
- 지연 로딩을 사용하면 캐시 효율성을 높일 수 있다. 필요한 시점에 로딩되는 지연 로딩은 캐시를 효과적으로 활용하여 반복적인 조회에 대한 성능을 향상시킬 수 있다. 반면 즉시 로딩은 모든 연관 엔티티를 한 번에 로딩하기 때문에, 캐시의 무결성을 유지하기 어려울 수 있다.
- 이러한 이유로 지연 로딩을 사용하여 성능 최적화, 네트워크 부하 감소, 데이터 일관성 유지, 복잡한 객체 그래프 처리, 캐시 효율성 향상 등의 장점을 얻을 수 있다.
<aside>
3️⃣ 즉시 로딩이 N+1문제를 발생시키는 이유 (지연 로딩을 써야하는 이유)
</aside>
- N+1 문제란 한 번의 쿼리로 연관된 엔티티를 조회하더라도, 연관 엔티티의 수만큼 추가적인 쿼리가 발생하는 문제를 말한다. 이는 즉시 로딩이 사용된 연관관계에서 주로 발생하는 현상이다.