Spring/강의

[📘 심화 Spring] 2-1. JPA 연관관계 매핑

가지코딩 2025. 6. 9. 17:02

📘 목차

  1. 연관관계 매핑
  2. 1 : N 연관관계
  3. 1 : 1 연관관계
  4. N : M 연관관계
  5. 상속관계 매핑

1. 연관관계 매핑

연관관계의 종류

  • 관계 타입
    • N:1 (ManyToOne)
    • 1:N (OneToMany)
    • 1:1 (OneToOne)
    • N:M (ManyToMany)
  • 방향성
    • 단방향: 한쪽 엔티티만 상대 엔티티를 참조
    • 양방향: 양쪽 엔티티가 서로를 참조

 

주요 어노테이션

관계 타입 어노테이션 비고
N : 1 @ManyToOne 가장 많이 사용됨
1 : N @OneToMany  
1 : 1 @OneToOne  
N : M @ManyToMany 신중하게 사용 권장

 

 

 

단방향과 양방향 연관관계

  • 테이블 관점
    • 외래 키(FK) 하나로 두 테이블 간 JOIN 가능
  • 객체 관점
    • 단방향: 외래키가 있는 쪽 엔티티만 상대 엔티티를 참조 가능
    • 양방향: 두 엔티티 모두 서로를 참조, 단방향 연관관계 두 개가 모여 양방향 관계가 됨

 

연관관계의 주인 (Owner)

  • 연관관계 주인: 외래키(FK)를 직접 관리하는 객체(엔티티)
  • 주인이 아닌 쪽: 단순 조회용으로만 사용 가능, 연관관계 변경 시 주인만 DB에 반영됨

 

요약

관계 타입 방향성 외래키 위치 연관관계 주인 특징
1 : N 단방향 N 쪽 테이블 1 쪽 N 쪽은 1 쪽 참조 못함
1 : N 양방향 N 쪽 테이블 N 쪽 양쪽 탐색 가능, N 쪽이 주인
1 : 1 단방향 참조하는 쪽 테이블 참조하는 쪽 외래키가 있는 쪽이 주인
1 : 1 양방향 외래키가 있는 쪽 외래키 쪽 양쪽 탐색 가능
N : M 단/양방향 중간 테이블 중간 테이블 중간 테이블에 속성 추가 어려움

 


2. 1 : N 연관관계

1 : N 단방향

  • 한 쪽(1)에만 연관관계가 설정되어 있음.
  • 예: Order → 여러 OrderItem (Order가 OrderItem을 참조하지만, OrderItem은 Order를 모름)
  • 구현: 보통 1(N) 쪽에 외래키가 있어서, 1 쪽에서 컬렉션으로 관리.
  • 문제점: 단방향이므로 N 쪽에서 1 쪽 참조가 불가능.
@Entity
public class Order {
  @Id
  private Long id;

  @OneToMany
  @JoinColumn(name = "order_id") // 외래키를 OrderItem 테이블에 생성
  private List<OrderItem> orderItems;
}

 

 

1 : N 양방향

  • 1 쪽과 N 쪽 모두가 서로를 참조.
  • 예: Order ↔ OrderItem
  • 구현: N 쪽에 외래키가 존재하며, N 쪽이 연관관계의 주인(owning side)임.
  • 1 쪽은 mappedBy 속성으로 연관관계의 주인이 아님을 명시.
  • 장점: 양쪽에서 객체 탐색 가능.
  • 주의점: 연관관계 관리 시 N 쪽 주인 쪽 객체를 변경해야 연관관계가 제대로 반영됨.
@Entity
public class Order {
  @Id
  private Long id;

  @OneToMany(mappedBy = "order")
  private List<OrderItem> orderItems;
}

@Entity
public class OrderItem {
  @Id
  private Long id;

  @ManyToOne
  @JoinColumn(name = "order_id")
  private Order order;
}

3. 1 : 1 연관관계

 

1 : 1 단방향

  • 한 쪽에서만 상대 객체를 참조.
  • 예: Member → Locker (Member가 Locker를 참조하지만 Locker는 Member를 모름)
  • 외래키를 어느 쪽에 둘지 결정해야 함.
@Entity
public class Member {
  @Id
  private Long id;

  @OneToOne
  @JoinColumn(name = "locker_id")
  private Locker locker;
}

 

 

1 : 1 양방향

  • 양쪽에서 서로 참조.
  • 외래키를 어느 쪽에 둘지 결정하며, 외래키가 있는 쪽이 연관관계의 주인임.
  • 주인은 외래키가 존재하는 쪽으로 지정.
@Entity
public class Member {
  @Id
  private Long id;

  @OneToOne(mappedBy = "member")
  private Locker locker;
}

@Entity
public class Locker {
  @Id
  private Long id;

  @OneToOne
  @JoinColumn(name = "member_id")
  private Member member;
}

 

 

1 : 1 연관관계 외래 키

  • 외래키는 보통 한 쪽 테이블에 단일 컬럼으로 존재.
  • 외래키는 반드시 유니크 제약조건이 있어야 1:1 관계를 보장.

4. N : M 연관관계

N : M 기본 매핑

  • 두 엔티티가 서로 다대다 관계.
  • 예: Student ↔ Course (학생은 여러 강의를 듣고, 강의는 여러 학생이 수강)
@Entity
public class Student {
  @Id
  private Long id;

  @ManyToMany
  @JoinTable(
    name = "student_course",
    joinColumns = @JoinColumn(name = "student_id"),
    inverseJoinColumns = @JoinColumn(name = "course_id")
  )
  private List<Course> courses;
}

@Entity
public class Course {
  @Id
  private Long id;

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

 

 

N : M 단방향, 양방향

  • 단방향: 한 쪽에서만 상대 객체를 참조.
  • 양방향: 서로 참조 가능.

 

N : M 매핑의 문제점

  • 중간 테이블에 추가 속성을 넣기 어렵다.
  • 실무에서는 중간 테이블을 엔티티로 분리해서 1:N, N:1 관계로 풀어 관리한다.

5. 상속관계 매핑

테이블 전략 종류

  • 단일 테이블 전략 (Single Table)
    • 모든 클래스 정보를 하나의 테이블에 저장.
    • 구분 컬럼(discriminator column)으로 어떤 클래스 인지 구분.
    • 장점: 조회 시 조인 불필요, 성능 우수.
    • 단점: NULL 컬럼 많아짐, 테이블 크기 커짐.
  • 조인 전략 (Joined)
    • 슈퍼클래스 테이블과 서브클래스 테이블을 분리.
    • 서브클래스는 슈퍼클래스 PK를 외래키로 참조.
    • 조회 시 조인 필요.
    • 장점: 정규화된 테이블 구조.
    • 단점: 조회 시 조인으로 인한 성능 저하 가능.
  • 테이블 per 클래스 전략 (Table per Class)
    • 각 클래스마다 별도의 테이블 생성.
    • 슈퍼클래스 필드 포함.
    • 조회 시 UNION 쿼리 사용.
    • 장점: 테이블 구조 단순.
    • 단점: UNION으로 조회 성능 저하 가능.

 

JPA의 테이블 전략 설정

  • @Inheritance(strategy = InheritanceType.SINGLE_TABLE)
  • @Inheritance(strategy = InheritanceType.JOINED)
  • @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
  • 구분 컬럼은 @DiscriminatorColumn으로 지정 가능하며, 기본값은 DTYPE.