[Spring] 일대다 연관관계

이연우·2025년 8월 19일

TIL

목록 보기
83/100

📖 연관관계 매핑이란?

  • JPA에서는 단순히 테이블만 다루는 것이 아니라,
    객체 지향적으로 엔티티(Entity) 간의 관계를 표현할 수 있음
  • 즉, SQL에서 FK(Foreign Key)를 직접 관리하지 않고,
    엔티티 간 참조를 통해 데이터를 가져오고 수정할 수 있도록 도와주는 기능

🔗 관계 종류

  • N:1@ManyToOne
  • 1:N@OneToMany
  • 1:1@OneToOne
  • N:M@ManyToMany (⚠️ 잘 쓰지 않음, 중간 테이블 관리 어려움)

🚦 단방향 vs 양방향

  • 테이블(DB)
    • 외래 키(FK) 하나만 있으면 JOIN으로 어느 방향이든 조회 가능
  • 객체(JAVA)
    • FK가 있는 객체만 상대방을 참조 가능 → 👉 단방향
    • 양쪽이 서로 참조할 수 있도록 필드가 있으면 → 👉 양방향
      (사실상 "단방향 2개"의 합)

🗝️ 연관관계의 주인 (Owner)

  • ✅ 외래 키를 직접 관리하는 객체
  • ❌ 주인이 아닌 경우 → 단순히 읽기만 가능 (수정 불가)

➡️ 1:N 단방향 관계

🖼️ 그림으로 이해

Company(1) ------> Tutor(N)
  • Company 엔티티가 @OneToMany를 통해 여러 Tutor 엔티티를 가짐
  • 하지만 DB 설계에서는 FK가 항상 N쪽(즉 Tutor 테이블)에 있어야 함
  • 따라서 Company에서 Tutor를 추가하면,
    실제로는 Tutor 테이블이 update 되어야 함 → 성능상 불리 ⚡

💻 코드 예시

@Entity
@Table(name = "company")
public class Company {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @OneToMany
    @JoinColumn(name = "company_id") // Tutor 테이블에 FK 생성
    private List<Tutor> tutors = new ArrayList<>();
}
@Entity
@Table(name = "tutor")
public class Tutor {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
}
  • 실행하면 Tutor 테이블에 company_id 컬럼이 추가됨
  • Companytutor를 추가하면 → Tutor 테이블에 update SQL 발생
    🚨 성능상 단점 존재

⚠️ @JoinColumn 미사용 시

@OneToMany
// @JoinColumn(name = "company_id") 생략
private List<Tutor> tutors = new ArrayList<>();
  • 이 경우 JPA는 중간 조인 테이블(company_tutor)을 생성해서 관리함
  • 불필요한 테이블이 생기므로 @JoinColumn은 필수로 붙여야 함!

💡 정리

  • 1:N 단방향은 성능과 구조가 어색하기 때문에 현업에서는 잘 쓰지 않음
  • 대신 N:1 양방향으로 풀어내는 것이 더 깔끔함

↔️ 1:N 양방향 관계

🖼️ 그림으로 이해

Company(1) <------> Tutor(N)
  • Company : Tutor 리스트(List<Tutor>)를 가짐
  • Tutor : 자신이 소속된 Company를 참조

💻 코드 예시

@Entity
@Table(name = "tutor")
public class Tutor {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @ManyToOne
    @JoinColumn(name = "company_id", insertable = false, updatable = false)
    private Company company; // 읽기 전용
}
  • Tutor 입장에서도 Company를 참조할 수 있음
  • 하지만 insertable=false, updatable=false 옵션을 주어
    읽기 전용으로 만들어야 함 (양쪽에서 동시에 수정 가능하면 혼란 발생 🚨)

🧠 요약 정리

구분1:N 단방향
(@OneToMany)
N:1 양방향
(@ManyToOne + @OneToMany)
🔑 외래 키 위치N쪽(Tutor)에 위치하지만,
1쪽(Company)이 관리
N쪽(Tutor)에 위치,
N쪽이 직접 관리
📝 연관관계 주인1쪽(Company) → 관리가 어색함N쪽(Tutor) → 자연스럽고 직관적
SQL 동작Company에서 Tutor 추가 시,
Tutor 테이블에 update 발생
(추가 SQL 필요)
Tutor persist 시 FK 즉시 저장
→ 불필요한 update 없음
🛠 구현 난이도복잡, 성능상 불리단순, 성능상 유리
🏗 DB 설계 적합성테이블 구조와 어긋남 (비추천)DB 설계와 잘 맞음 (권장)
🗂 @JoinColumn 미사용 시중간 테이블 생성됨 (불필요)자연스럽게 FK만 사용
실무 활용거의 사용하지 않음가장 많이 사용되는 패턴

0개의 댓글