[Spring] 다대다 연관관계

이연우·2025년 8월 19일

TIL

목록 보기
85/100

📖 N:M 연관관계란?

  • 두 엔티티가 서로 다수의 관계를 맺는 경우 → @ManyToMany

📚 예시

  • 한 명의 Tutor는 여러 개의 Language를 사용할 수 있음
  • 동시에 하나의 Language도 여러 Tutor가 사용할 수 있음

📦 객체 관점

Tutor(1..N) ◀───▶ Language(1..N)
  • Collection을 사용하여 N:M 설정이 가능함
  • 여러 명의 Tutor가 여러 개의 Language를 사용할 수 있음

🗄️ 데이터베이스 관점

  • 관계형 DB는 직접적인 N:M 관계를 지원하지 않음

  • 따라서 중간 테이블을 만들어서 1:N, N:1로 풀어야 함


💡 N:M 단방향, 양방향

🔹 단방향 예시

@ManyToMany
@JoinTable(
    name = "tutor_language",
    joinColumns = @JoinColumn(name = "tutor_id"),
    inverseJoinColumns = @JoinColumn(name = "language_id")
)
private List<Language> languages = new ArrayList<>();
  • tutor_language라는 중간 테이블 자동 생성
  • TutorLanguage 참조 가능

🔹 양방향 예시

@ManyToMany(mappedBy = "languages")
private List<Tutor> tutors = new ArrayList<>();
  • Language에서도 Tutor를 참조 가능
  • mappedBy를 통해 반대쪽은 읽기 전용
  • @OneToOne 양방향과 비슷하지만, 내부적으로는 중간 테이블 사용

⚠️ N:M 매핑의 문제점

💡 @ManyToMany는 편리해 보이지만 실제로는 문제점이 많음

1. 추가 데이터 불가

  • 예: TutorLanguage 사이에 level, license 같은 속성을 넣을 수 없음
  • 비즈니스 로직에서 이런 속성이 필요한 경우가 대부분
  • 🚫 @ManyToMany단순 연결만 가능

2. 숨겨진 중간 테이블

  • SQL을 직접 제어하기 어려움
  • 예상치 못한 쿼리 발생 가능

3. 복합 PK 문제

  • 중간 테이블의 PK가 (tutor_id, language_id) 복합 키로 생성
  • 복합 키 기반은 확장성과 관리 측면에서 불리

✅ 문제 해결 방법

→ 중간 테이블을 실제 엔티티로 만들어서 관리하면 됨

🔹 중간 테이블 엔티티 (예: TutorLanguage)

@Entity
@Table(name = "tutor_language")
public class TutorLanguage {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;  // 단일 PK

    @ManyToOne
    @JoinColumn(name = "tutor_id")
    private Tutor tutor;

    @ManyToOne
    @JoinColumn(name = "language_id")
    private Language language;

    private Integer level;   // 추가 속성
    private String license;  // 추가 속성
}

🔹 Tutor 엔티티

@OneToMany(mappedBy = "tutor")
private List<TutorLanguage> tutorLanguages = new ArrayList<>();

🔹 Language 엔티티

@OneToMany(mappedBy = "language")
private List<TutorLanguage> tutorLanguages = new ArrayList<>();

🚀 실행 결과

  • tutor_language 테이블이 엔티티로 생성됨
  • 이제 level, license 같은 부가 정보도 함께 저장 가능
  • 단일 PK(id)로 관리하기 때문에 확장성도 좋아짐

🧠 요약 정리

구분@ManyToMany 직접 사용중간 엔티티(TutorLanguage) 사용
🔗 구조자동 중간 테이블 생성중간 테이블을 엔티티로 정의
📝 추가 속성불가능 ❌가능 (예: level, license) ✅
SQL 제어제약 많음, 숨겨짐명시적 제어 가능
🔑 PK 구조복합키 (tutor_id, language_id)단일 PK (id)
🛠️ 유지 보수확장 어려움유연하고 확장성 높음
실무 활용거의 사용하지 않음권장되는 방식

0개의 댓글