본문 바로가기
spring

[Spring] JPA 연관관계

by goblin- 2024. 12. 4.

JPA에서 연관관계를 정의할 때 주로 사용되는 관계는 일대일(1:1), 일대다(1:N), 다대일(N:1), 다대다(N:M) 네 가지입니다. 각각의 관계는 엔티티 간의 데이터 참조 방식에 따라 결정되며, 이를 정의하기 위해 JPA에서는 어노테이션을 사용합니다.

 

아래에서 각 연관관계의 특징과 구현 방법을 설명하고, 예제를 제공합니다.

 

1. 일대일 (One-to-One)

 

특징

 

한 엔티티는 다른 엔티티와 1:1로 매핑됩니다.

두 엔티티 중 하나가 외래 키를 소유하거나, 별도의 테이블을 통해 관계를 설정할 수 있습니다.

 

예제: 사용자와 프로필

@Entity
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @OneToOne(mappedBy = "user", cascade = CascadeType.ALL)
    private Profile profile;
}

@Entity
public class Profile {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String bio;

    @OneToOne
    @JoinColumn(name = "user_id") // 외래 키
    private User user;
}

 

주요 어노테이션

 

@OneToOne: 일대일 관계를 나타냄.

@JoinColumn: 외래 키를 정의. (여기선 Profile이 외래 키를 소유)

 

@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "profile_id") // 외래 키
private Profile profile;

 

속성 설명 기본값
cascade 부모 엔티티의 작업(Persist, Remove 등)을 자식 엔티티에 전파.(CascadeType 열거형 사용) 없음
fetch 데이터를 가져오는 방식 (FetchType.LAZY or FetchType.EAGER) FetchType.EAGER
mappedBy 양방향 관계에서 외래 키를 관리하는 빌드 지정(연관 관계의 주인을 정의). 없음
optional 관계 대상 엔티티가 null이어도 되는지 여부 설정 true
orphanRemoval 부모 엔티티와의 관계가 끊어진 자식 엔티티를 자동 삭제 false

 

 

2. 다대일 (Many-to-One)

 

특징

 

여러 엔티티가 하나의 엔티티를 참조합니다.

주로 관계의 주인은 “다”쪽에 설정됩니다.( 관계의 주인은 외래 키를 소유하고 관리하는 엔티티)

 

예제: 주문과 사용자

@Entity
public class Order {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String productName;

    @ManyToOne
    @JoinColumn(name = "user_id") // 외래 키
    private User user;
}

@Entity
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
    private List<Order> orders = new ArrayList<>();
}

주요 어노테이션

 

@ManyToOne: 다대일 관계를 나타냄.

@JoinColumn: 외래 키를 정의.

 

@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
@JoinColumn(name = "user_id", nullable = false) // 외래 키
private User user;

 

속성 설명 기본값
cascade 부모 엔티티 작업을 자식 엔티티에 전파. 없음
fetch 데이터를 가져오는 방식(FetchType.LAZY or FetchType.EAGER) FetchType.EAGER
optional 관계 대상 엔티티가 null이어도 되는지 여부 설정. true

 

3. 일대다 (One-to-Many)

 

특징

 

한 엔티티가 여러 엔티티를 참조합니다.

@OneToMany는 기본적으로 관계의 주인이 아니므로, 외래 키는 @ManyToOne 쪽에 설정됩니다.

 

예제: 사용자와 주문

@Entity
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
    private List<Order> orders = new ArrayList<>();
}

@Entity
public class Order {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String productName;

    @ManyToOne
    @JoinColumn(name = "user_id") // 외래 키
    private User user;
}

 

주요 어노테이션

 

@OneToMany: 일대다 관계를 나타냄.

mappedBy: 관계의 주인을 설정. (user 필드와 매핑)

 

@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Order> orders = new ArrayList<>();

 

속성 설명 기본값
cascade 부모 엔티티 작업을 자식 엔티티에 전파. 없음
fetch 데이터를 가져오는 방식(FetchType.LAZY or FetchType.EAGER). FetchType.LAZY
mappedBy 양방향 관계에서 외래 키를 관리하는 필드 지정(연관 관계의 주인을 정의). 없음
orphanRemoval 부모 인티티와의 관계가 끊어진 자식 엔티티를 자동 삭제 false

 

 

4. 다대다 (Many-to-Many)

 

특징

 

여러 엔티티가 여러 엔티티와 참조 관계를 가집니다.

다대다 관계는 중간 테이블을 사용하여 매핑합니다.

 

예제: 학생과 수업

@Entity
public class Student {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @ManyToMany
    @JoinTable(
        name = "student_course", // 중간 테이블
        joinColumns = @JoinColumn(name = "student_id"),
        inverseJoinColumns = @JoinColumn(name = "course_id")
    )
    private List<Course> courses = new ArrayList<>();
}

@Entity
public class Course {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String title;

    @ManyToMany(mappedBy = "courses")
    private List<Student> students = new ArrayList<>();
}

 

주요 어노테이션

 

@ManyToMany: 다대다 관계를 나타냄.

@JoinTable: 중간 테이블 정의.

joinColumns: 현재 엔티티의 외래 키 설정.

inverseJoinColumns: 상대 엔티티의 외래 키 설정.

@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinTable(
    name = "student_course",
    joinColumns = @JoinColumn(name = "student_id"),
    inverseJoinColumns = @JoinColumn(name = "course_id")
)
private List<Course> courses = new ArrayList<>();

 

속성 설명 기본값
casacade 부모 엔티티 작업을 자식 엔티티에 전파 없음
fetch 데이터를 가져오는 방식(FetchType.LAZY or FetchType.EAGER). FetchType.LAZY
mappedBy 양방향 관계에서 외래 키를 관리하는 필드 지정. 없음

 

5. 양방향과 단방향

 

단방향: 한쪽에서만 연관 관계를 정의.

간단하고 직관적이며, 관계가 간단할 때 적합.

양방향: 양쪽 엔티티에서 서로를 참조.

mappedBy를 통해 관계의 주인을 설정해야 함.

관계를 명확히 하고 데이터를 쉽게 탐색 가능.

 

단방향 예제

@Entity
public class Order {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String productName;

    @ManyToOne
    @JoinColumn(name = "user_id")
    private User user;
}

 

양방향 예제

@Entity
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @OneToMany(mappedBy = "user")
    private List<Order> orders = new ArrayList<>();
}

@Entity
public class Order {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String productName;

    @ManyToOne
    @JoinColumn(name = "user_id")
    private User user;
}

 

6. Cascade와 Fetch 옵션

 

(1) Cascade

 

연관 엔티티를 함께 저장, 삭제할 때 사용.

주요 옵션:

CascadeType.PERSIST: 부모 저장 시 자식도 저장.

CascadeType.REMOVE: 부모 삭제 시 자식도 삭제.

CascadeType.ALL: 모든 Cascade 옵션 적용.

 

(2) Fetch

 

연관 데이터를 언제 가져올지 설정.

주요 옵션:

FetchType.LAZY: 연관 데이터를 실제로 사용할 때 조회(기본값).

FetchType.EAGER: 엔티티를 조회할 때 즉시 연관 데이터도 함께 조회.

 

7. 정리

 

연관 관계는 비즈니스 요구사항에 따라 선택.

단방향과 양방향 관계를 적절히 설계.

성능 최적화를 위해 CascadeFetch 전략을 신중히 선택.

'spring' 카테고리의 다른 글

[Spring] Jackson  (0) 2024.12.17
[Spring] JWT기반 로그인 예시  (0) 2024.12.11
[Spring] JPA  (0) 2024.12.03
[Spring] 프록시(proxy)  (0) 2024.11.30
[Spring] AOP 실제 적용 예시  (1) 2024.11.29