연관관계와 mappedBy

랏 뜨·2024년 12월 17일

🔎 Overview

  처음 엔티티를 만들고 JPA를 통해 DB와 연동을 할 때, @OneToManyManyToOne 을 적용하면서 힘들었던 기억이 난다.

  이 부분에서 가장 어려웠던 부분은 이전까지는 잘 되던 프로젝트가 엔티티 간의 연관관계를 맺고 다시 실행하니 갑자기 컴파일 오류가 발생했던 것이었다.
엔티티 생성만 하는 것은 문제가 없었지만, 값을 가져올 때 문제가 생겼다.
이는 @OneToMany 의 기본 FetchTypeLAZY이기 때문에 발생한 것이다.
해당 부분에 대해서는 이전에 Proxy 포스팅에서 정리해두었다.

  그 외에도 @OneToMany 를 달아줄 때 옵션으로 달았던 mappedBy나, 연관관계와 연관관계의 주인 등 헷갈리는 개념들이 많이 등장했다.

  그래서 이번에는 연관관계mappedBy 옵션에 대해서 정리해보고자 한다.


❕ Entity

연관관계에 대해 정리하기에 앞서, 간단하게 엔티티의 정의를 먼저 살펴보자.

  • 데이터베이스 테이블에 매핑되는 자바 클래스
  • @Entity 어노테이션을 사용하여 정의
  • Row -> 클래스의 객체들 (값)
  • Column -> 클래스의 필드

📕 연관관계

  • 두 개 이상의 엔티티 간의 관계
  • 객체 지향적 관계(Class 객체)RDB의 테이블 간 관계로 변환하는 작업
  • DB의 외래 키를 기반으로 객체 간의 관계를 표현
  • 연관관계의 종류는 총 4가지가 있으며, 어노테이션으로 매핑

💪 연관관계의 주인

  • 양방향 연관관계에서 외래 키를 가지고 데이터를 관리하는 엔티티
  • 비주인 엔티티는 외래 키를 관리하지 않음

⭐ mappedBy

  • 연관관계에서 비주인 엔티티가 연관관계의 주인을 정의할 때 사용
  • 양방향 연관관계에서 주인 엔티티의 필드명을 지정

‼️ Tip

1) mappedBy 로 필드를 지정하지 않을 경우

  • 엔티티 사이의 중간 테이블을 생성
  • 중간 테이블에서 외래 키를 관리

2) mappedBy 로 필드를 지정할 경우

  • 주인 엔티티에서 외래 키를 관리
  • N대N 관계를 제외하곤 중간 테이블이 생성되지 않음
  • N대N 관계는 중간 테이블을 반드시 생성하고, 주인 엔티티에서 중간 테이블을 외래 키로 관리

📋 연관관계의 종류

  • 연간관계의 종류는 크게 2가지, 총 4가지로 나뉨
  • 단방향 연간관계
    • 한 쪽에서만 다른 객체를 참조
    • A 객체는 B 객체를 참조하지만, B 객체는 A 객체를 참조하지 않음
  • 양방향 연간관계
    • 양쪽 객체가 서로를 참조
    • A 객체도 B 객체를 참조하고, B 객체도 A 객체를 참조

🌐 연관관계 매핑 어노테이션

1) @OneToOne

  • 1대1 관계
    • 두 엔티티가 서로 1:1로 매핑되는 관계
@Entity
public class User {
	// 생략
    
    @OneToOne
    @JoinColumn		// @JoinColumn은 필드명이 테이블과 같다면 생략 가능
    private Profile profile;
}

@Entity
public class Profile {
	// 생략
    
    @OneToOne(mappedBy = "profile")
    private User user;
}
  • mappedBy 옵션으로 연관관계 주인의 외래 키 필드명profile을 지정
  • 따라서 Profile 클래스는 연관관계의 주인이 아님
  • 연관관계의 주인은 User

2) @OneToMany

  • 1대N 관계
    • 한 엔티티가 여러 다른 엔티티를 참조하는 관계
@Entity
public class Team {
	// 생략
    
    @OneToMany(mappedBy = "team")
    private List<Member> members;
}

public class Member {
	// 생략
    
    @ManyToOne
    private Team team;
}
  • mappedBy 옵션으로 지정해준 team이 외래 키를 관리
  • 연관관계의 주인은 Member
  • 위 예시에서는 Team 엔티티에서 Member 엔티티 참조 가능 (양방향)

3) @ManyToOne

  • N대1 관계
    • 여러 엔티티가 하나의 엔티티를 참조할 때 사용
@Entity
public class Memeber {
	// 생략
    
    @ManyToOne
    private Team team;
}

@Entity
public class Team {
	// 생략   
}
  • 위 예시는 단방향 연간관계
  • 따라서 Team 엔티티에서는 Memeber 엔티티에 접근할 수 없음
  • 자동으로 연관관계의 주인은 Member 클래스이며, 외래 키는 team에서 관리

4) @ManyToMany

  • N대N 관계
    • 여러 엔티티가 여러 다른 엔티티와 관계
@Entity
public class Student {
	// 생략
    
    @ManyToMany
    private List<Course> courses;
}

@Entity
public class Course {
	// 생략
    
    @ManyToMnay(mappedBy = "course")
    private List<Student> students
}
  • mappedBy 로 지정된 course 필드가 있는 Student 클래스가 연관관계의 주인
  • @ManyToMany의 경우 항상 중간 테이블을 생성
  • 주인의 외래 키는 중간 테이블을 참조 및 관리
  • 주인이 아닌 Course 는 중간 테이블의 참조만 가능할 뿐, 갱신 등의 작업은 진행할 수 없음
  • 이는 데이터 일관성성능 최적화를 위함

참고) OpenAI. (2024).ChatGPT(4o)[Large language model].https://chatgpt.com/

profile
기록

0개의 댓글