JPA

[JPA] 다중성이란?

tudamoa 2025. 6. 26. 15:20

✅ 다중성(Multiplicity) 정의

두 엔티티(객체, 테이블) 사이의 개수 관계를 나타내는 것.

 

 

📌 다중성의 종류

관계 유형 설명 예시
일대일 (1:1) 한 객체는 상대 객체 하나만 가질 수 있음 사람(1) ↔ 주민등록증(1)
일대다 (1:N) 한 객체가 상대 객체 여러 개 가질 수 있음 회원(1) ↔ 게시글(N)
다대일 (N:1) 여러 객체가 같은(하나의) 상대 객체를 가질 수 있음 게시글(N) ↔ 하나의 회원(1)
다대다 (N:M) 여러 객체가 여러 상대 객체를 가질 수 있음 학생(N) ↔ 수강 과목(M)

 

다대일과 일대다는 서로 반대되는 개념이고 다대다는 서로가 서로를 여러 개씩 가지는 경우이다.

 

 

📐 다중성은 어디에 쓰이나?

  • 객체 모델 설계 시 → 어떤 관계로 매핑할지 결정
  • JPA, ERD 등에서 → 연관관계를 시각화하거나 코드로 표현할 때 기준
  • 외래키 설정, 컬렉션(List) 사용 여부, 조인 테이블 필요 여부 등 설계의 출발점

✅ 다중성을 잘 이해하고 적용해야 더욱 효율적으로 ORM을 사용할 수 있다.

 


 

🎯 다중성 설정 예시

  • Order ↔ Product
    → 하나의 주문에 여러 상품 포함, 하나의 상품은 여러 주문에 포함될 수 있음
    N:M (다대다) 다중성
  • Member ↔ Post
    → 한 명의 회원이 여러 개의 게시글을 쓴다
     1:N (일대다) 다중성

 

📌 1:N이 아니라 N:1 일수도 있지 않을까?

🔁 다중성은 관점에 따라 표현 방식이 달라진다.

관점 표현 방식
Member 기준 한 명의 회원은 여러 게시글을 가짐 → 1:N
Post 기준 여러 게시글은 각각 하나의 회원에게 속함 → N:1
 

동일한 관계이지만 관점을 어디에 두느냐에 따라 표현이 다를 수 있다.

 양쪽 관계를 모두 고려한 뒤 설계 관점에서 더 효율적인 방향으로 설계.

 

 

📌 왜 다중성(1:N vs N:1) 방향 설정이 중요한가?

▶ 단순한 표현 문제 X

단지 "Member가 Post를 가리킬까? Post가 Member를 가리킬까?”의 문제가 아니다.

실제 JPA 설계에서는 다중성 방향연관관계의 주인참조 방향 결정에 관련되어 있기 때문이다.

 

 

🎯 다중성과 연관관계의 주인

  • 연관관계의 주인이란 JPA가 실제로 외래키를 관리할 수 있는 쪽(엔티티)을 말한다
  • 데이터베이스에서 외래키는 1과 N 중에서 N인 테이블에 존재한다.
  • 연관관계의 주인인 테이블이 insert/update 쿼리를 날릴 수 있다.

 

객체 / 테이블 상황 예시

POST (테이블) MEMBER (테이블)
POST_ID (PK) MEMBER_ID (PK)
MEMBER_ID (FK) NAME
TITLE  

 

상황1                                                                                          상황2

Post (객체) Member (객체)   Post (객체) Member (객체)
id id   id id
Member member name   Title List Posts
Title       name

 

관점 다중성 참조
Post → Member 상황1 N:1 (다대일) Member 객체를 참조함
Member → Post 상황2 1:N (일대다) Post 객체를 List 형태로 가지고 있음

상황1: N:1에서는 Post가 Member를 참조하고 있으며 Post가 연관관계의 주인이다. 실제 외래키도 POST가 갖고 있다.

상황2: 1:N에서는 Member가 post를 참조하고 있지만 실제 외래키는 POST에 있다.
    연관관계의 주인은 Member지만 외래키는 Post 테이블에 있기 때문에 반대편 테이블의 외래키를 조작하기 위해
    불필요한 쿼리문이 발생하게 된다.

 

따라서 상황1로 다중성을 설정하는 것이 좀 더 효율적이라는 결론을 지을 수 있다.

 

🔁 방향성과 연관관계 설정 예

  • 단방향
    • Post → Member 단방향이면, 외래키도 Post에 있고 주인도 Post
  • 양방향
    • Post → Member, Member → Post 둘 다 선언
    • 이때 주인은 여전히 외래키 가진 Post
@Entity
public class Post {
    @ManyToOne // 다대일, 외래키가 존재하므로 연관관계 주인
    @JoinColumn(name = "member_id")  // @JoinColumn으로 외래키 설정(member열을 member_id로)
    private Member member;
}

@Entity
public class Member {
    @OneToMany(mappedBy = "member")  // 오직 읽기 전용 참조, 연관관계 주인 아님
    private List<Post> posts = new ArrayList<>();
}


💡 실무 팁

  • 처음엔 단방향으로 설계, 나중에 양방향이 필요해지면 추가
  • 불필요한 양방향은 유지보수, 무한루프, 성능 문제 등을 일으킬 수 있음.

 

✅ 정리: 왜 다중성 방향을 고려해야 할까?

  • 다중성은 단순한 수학적 표현이 아니다.
  • JPA에서는 누가 외래키를 갖는지, 누가 관계를 관리하는지, 쿼리를 어디서 발생시키는지까지 연결된다.
  • 따라서 다중성 방향은 단순하게 결정하는 것이 아니라:
    • 어떤 쪽이 주인(Owner)이 되는 게 자연스러운가?
    • 비즈니스 로직상 어떤 테이블로 데이터를 조회, 수정, 삭제할 가능성이 더 큰가?
    • 어떤 방향이 불필요한 쿼리나 성능 저하를 피할 수 있는가?

 


📐 설계 예시

상황: 회원(Member)과 게시글(Post)

  • 질문: 연관관계를 어떤 방향으로 맺어야 할까?

👉 양쪽 관점 분석

관점 관계 필요 여부 이유
Post → Member @ManyToOne 
Post 관점에서 다대일(N:1)
✅ 거의 필수 글 작성자 정보는 자주 조회됨
Member → Post @OneToMany(mappedBy="member")
Member 관점에서 일대다(1:N)
❌ 또는 조건부 회원이 작성한 글을 자주 조회하는 경우만 필요

 

⚙️ 판단 기준 3가지

 

1. 비즈니스 요구

  • 이 화면/기능에서 어떤 데이터가 자주 사용되는가?

2. 성능 (쿼리 수, fetch join 가능 여부 등)

  • 양방향 추가할 때 → 성능 손해 없이 필요한가?

3. 객체 그래프 탐색 필요 여부

  • member.getPosts()로 꺼내 써야 하는 로직이 많다면 양방향이 유리

 


 

✅ 1. 1:N (일대다)

1) 단방향 (비추천)

@Entity
public class Member {
    @OneToMany
    @JoinColumn(name = "member_id") // 외래키가 여기 있다는 의미
    private List<Post> posts = new ArrayList<>();
}
  • Post가 외래키를 가져야 자연스러운데 거꾸로 설계됨
  • → INSERT + UPDATE 두 번 쿼리 발생
  • ❌ 실무에서는 지양

 

2) 양방향 

@Entity
public class Member {
    @OneToMany
    @JoinColumn(name = "member_id") // 이게 주인처럼 보이게 만듦
    private List<Post> posts;
}

@Entity
public class Post {
    @ManyToOne(mappedBy = "posts")  // ❌ 잘못된 구조 — JPA는 이런 걸 지원하지 않음
    private Member member;
}
  • 외래키는 Post에 존재
  • 주인은 Post, Member.posts는 읽기 전용

 

굳이 1:N 양방향을 하고 싶다면?

✅ 방법

// Member
@OneToMany
@JoinColumn(name = "member_id")
List<Post> posts;

// Post
@ManyToOne
@JoinColumn(name = "member_id", insertable = false, updatable = false)
Member member;

❌ 그러나 추천 X

  • 일대다 양방향으로 쓰고 싶다면 다대일 양방향으로 설계하는 것이 나음.
  • 외래키는 항상 다 쪽에 두는 게 JPA 철학에 맞고 쿼리 효율도 훨씬 좋음.

 

✅ 2. N:1 (다대일)

1) 단방향

@Entity
public class Post {
    @ManyToOne
    @JoinColumn(name = "member_id")
    private Member member;
}
  • 외래키가 Post에 있음
  • 가장 간단하고 실용적인 단방향 연관관계

 

2) 양방향 (= 1:N 양방향과 거의 동일)

@Entity
public class Post {

    @Id @GeneratedValue
    private Long id;

    @ManyToOne
    @JoinColumn(name = "member_id") // 외래키 → 연관관계 주인
    private Member member;
}

@Entity
public class Member {

    @Id @GeneratedValue
    private Long id;

    @OneToMany(mappedBy = "member") // Post.member를 기준으로 연관관계 해석
    private List<Post> posts = new ArrayList<>();
}

 

✅ 3. N:M (다대다)

  • 실무에서는 잘 안 씀.
  • 중간 테이블을 두고 @OneToMany, @ManyToOne 을 활용해서 할 수 있긴 함.

 

✅ 4. 1:1 (일대일)

1) 단방향

@Entity
public class User {
    @OneToOne
    @JoinColumn(name = "profile_id")
    private Profile profile;
}
  • User가 외래키 가짐 → 연관관계의 주인

 

2) 양방향

@Entity
public class User {
    @OneToOne
    @JoinColumn(name = "profile_id")
    private Profile profile;
}

@Entity
public class Profile {
    @OneToOne(mappedBy = "profile")
    private User user;
}
  • User가 외래키 소유 (주인), Profile은 비주인
  • ❗1:1 관계는 어느 쪽이 외래키 가질지 잘 고민해야 함.
    (자주 조회하는 쪽, PK 재사용 여부 등 고려)

'JPA' 카테고리의 다른 글

[JPA] QueryDSL 이란?  (0) 2025.06.28
[JPA] Fetch Join이란?  (0) 2025.06.25
[JPA] N+1 문제 원인 & 해결  (0) 2025.06.24