카테고리 없음

[SpringBoot] Many-to-One & One-to-Many 관계

codi-3 2024. 9. 13. 18:44

Spring Boot와 JPA에서 Many-to-One과 One-to-Many 관계는 매우 자주 사용되며, 이 관계의 Fetch 타입을 잘 이해하는 것이 성능 최적화에 매우 중요하다. 

 

Many-to-One (n:1) 관계

Many-to-One 관계는 여러 엔터티가 하나의 엔터티에 매핑되는 상황이다. 예를 들어, 여러 Employee가 하나의 Department에 속할 수 있

다.

예시: Employee와 Department의 Many-to-One 관계

import jakarta.persistence.*;

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

    // Getter, Setter 생략
}

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

    @ManyToOne(fetch = FetchType.LAZY)  // 지연 로딩으로 설정
    @JoinColumn(name = "department_id")  // 외래키가 되는 department_id를 매핑
    private Department department;  // 여러 직원이 하나의 부서에 속함

    // Getter, Setter 생략
}

설명:

  • @ManyToOne: Employee는 여러 개이고, 각각 하나의 Department에 속합니다.
  • fetch = FetchType.LAZY: Department 엔터티는 실제로 접근하기 전까지 조회되지 않는다. 이를 지연 로딩(Lazy Loading)이라고 하며, 성능 최적화에 도움이 된다.
  • fetch = FetchType.EAGER로 설정하면 Employee를 조회할 때 관련된 Department도 즉시 같이 조회된다.

One-to-Many (1) 관계

One-to-Many 관계는 하나의 엔터티가 여러 엔터티와 연결되는 상황입니다. 예를 들어, 하나의 Department에 여러 명의 Employee가 있을 수 있습니다.

예시: Department와 Employee의 One-to-Many 관계

import jakarta.persistence.*;
import java.util.List;

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

    @OneToMany(mappedBy = "department", fetch = FetchType.LAZY, cascade = CascadeType.ALL)  // 지연 로딩과 Cascade 설정
    private List<Employee> employees;  // 하나의 부서에 여러 명의 직원이 있음

    // Getter, Setter 생략
}

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

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "department_id")
    private Department department;

    // Getter, Setter 생략
}

설명:

  • @OneToMany: 하나의 Department는 여러 Employee와 연결된다.
  • mappedBy: OneToMany 관계에서는 반대쪽 엔터티(Employee)에서 매핑할 필드를 지정한다. 즉, Employee의 department 필드와 연결된다.
  • fetch = FetchType.LAZY: 기본적으로 OneToMany 관계는 지연 로딩으로 설정된다. 즉, Department를 조회할 때, employees 필드는 실제로 필요할 때만 조회된다.
  • cascade = CascadeType.ALL: Department가 삭제되면 관련된 모든 Employee도 같이 삭제된다. 이런 방식으로 자식 엔터티도 같이 처리된다.

FetchType 설명

  • FetchType.LAZY: 지연 로딩으로, 관련 엔터티는 실제로 접근할 때까지 데이터베이스에서 조회되지 않는다. 성능 최적화에 유리하지만, 관계를 사용하는 시점에 추가적인 쿼리가 발생할 수 있다.
  • FetchType.EAGER: 즉시 로딩으로, 관련 엔터티가 함께 조회됩니다. 데이터베이스에서 즉시 모두 가져오기 때문에 여러 엔터티를 한 번에 처리할 수 있지만, 불필요한 데이터를 미리 조회하는 경우 성능에 영향을 줄 수 있다.

주석 설명:

  1. @ManyToOne: n:1 관계를 설정하는 어노테이션. (Default = FetchType.EAGER)
  2. @OneToMany: 1:n 관계를 설정하는 어노테이션. (Default = FetchType.LAZY)
  3. fetch = FetchType.LAZY: 지연 로딩을 사용하여 성능 최적화를 하는 방식.
  4. @JoinColumn: 외래키를 지정하는 어노테이션.
  5. mappedBy: 관계를 정의할 때 반대쪽 엔터티의 필드명을 지정하여 양방향 관계를 설정.
  6. cascade = CascadeType.ALL: 부모 엔터티에서 자식 엔터티로의 연쇄 작업을 설정 (예: 삭제, 저장 시).