@OneToMany와 FetchType.LAZY 이해하기

coldrice99·2024년 11월 10일
0
post-thumbnail

이번 글에서는 @OneToMany 관계와 FetchType.LAZY 옵션을 간단히 설명하겠습니다. 이 두 가지는 데이터베이스와 연결된 엔티티들이 어떻게 불러와지는지를 제어하는 데 중요한 역할을 합니다.


1. @OneToMany 관계란?

@OneToMany'하나가 여러 개를 가진다'는 의미로, 예를 들어 한 명의 사용자(Member)여러 개의 게시물(Post)을 작성할 수 있는 상황을 표현할 때 사용합니다.

@Entity
public class Member {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String name;

    // Member는 여러 개의 Post를 가질 수 있다
    @OneToMany(mappedBy = "member")
    private List<Post> posts = new ArrayList<>();
}

위 코드에서 Member 클래스는 여러 개의 Post를 가지는 @OneToMany 관계를 가지고 있습니다. mappedBy = "member"는 이 관계의 주인이 Post 엔티티의 member 필드임을 뜻합니다. 즉, Post 쪽에서 Member와의 관계를 관리하고, Member는 연결만 가지고 있는 것입니다.

@OneToMany 관계는 기본적으로 FetchType.LAZY로 설정되어 있습니다. 즉, 명시적으로 설정하지 않아도 연관 데이터는 필요할 때만 가져오게 됩니다.


2. FetchType.LAZY란?

FetchType.LAZY는 JPA가 데이터를 가져오는 방식을 제어하는 옵션입니다. 주로 성능을 높이기 위해 연관 데이터를 미리 불러오지 않고, 실제로 필요한 순간에 가져오도록 하는 방식입니다.

  • Lazy Loading: 연관된 데이터가 실제로 필요할 때, 즉 접근하려고 할 때만 데이터베이스에서 가져옵니다.
  • Eager Loading: 연관된 데이터를 즉시 모두 가져오는 방식으로, 처음부터 모든 데이터를 미리 불러옵니다.
@OneToMany(mappedBy = "member", fetch = FetchType.LAZY)
private List<Post> posts;

위 코드에서 fetch = FetchType.LAZY로 설정했기 때문에, Member 객체를 조회하더라도 Post 목록은 즉시 가져오지 않습니다. Member 객체의 posts 필드에 접근하려고 하는 순간에 데이터베이스 쿼리가 실행됩니다. 따라서 불필요한 데이터를 미리 로딩하지 않아 성능을 최적화할 수 있습니다.


3. FetchType.LAZY의 장점과 주의사항

Lazy Loading은 필요한 데이터를 그때그때 가져오기 때문에 메모리와 성능을 효율적으로 사용할 수 있습니다. 그러나 주의할 점은 N+1 문제라고 불리는 현상인데, 이는 다수의 Member를 조회할 때 각 Member의 Post를 개별적으로 가져오면서 쿼리가 여러 번 실행되는 상황을 말합니다. 예를 들어, 10명의 Member를 조회하고 각 Member의 Post 목록을 가져온다면 최대 11번의 쿼리가 발생할 수 있습니다 (1번은 Member를 조회하는 쿼리, 10번은 각각의 Post 목록을 가져오는 쿼리).

이를 해결하기 위해 Fetch Join을 사용하여 한 번의 쿼리로 모든 데이터를 가져오는 방식도 있습니다.

// Fetch Join 사용 예시
public List<Member> findAllMembersWithPosts() {
    return em.createQuery(
        "SELECT m FROM Member m JOIN FETCH m.posts", Member.class)
        .getResultList();
}

위처럼 Fetch Join을 사용하면 MemberPost를 한 번에 가져와서 N+1 문제를 해결할 수 있습니다.


4. 요약

  • @OneToMany: 하나의 객체가 여러 개의 다른 객체와 관계를 맺을 때 사용. 기본 설정은 FetchType.LAZY로 되어 있음.
  • FetchType.LAZY: 연관 데이터를 즉시 불러오지 않고, 실제 필요할 때 가져오는 방식. 성능 최적화에 유리.
  • N+1 문제: 여러 데이터를 조회할 때 개별 쿼리가 여러 번 실행되는 문제. Fetch Join을 통해 해결 가능.
profile
서두르지 않으나 쉬지 않고

0개의 댓글