✅ 연관관계 매핑이란?
- JPA에서는 RDB의 외래 키 기반 관계(FK)를 객체 간에 참조로 매핑한다.
- SQL 없이 객체지향적으로 테이블 간의 관계를 활용 가능
✅ 연관관계 종류
1️⃣ 단방향
- 한 쪽 엔티티만 다른 엔티티를 참조 (객체 그래프 탐색이 한 방향만 가능)
2️⃣ 양방향
- 양쪽 모두 서로 참조
- 연관관계의 주인이 존재 (외래 키 관리하는 엔티티)
- 주인만 DB에 반영, 반대쪽은 단순 조회용
객체 기준 단방향 2개 = 양방향
✅ 연관관계의 주인
JPA는 양방향 연관관계에서 외래 키(Foreign Key)를 기준으로 연관관계를 설정한다.
이때 DB의 외래 키를 실제로 관리하는 쪽이 연관관계의 주인이 된다. 반대쪽은 단순히 연관관계를 표현하기만 한다.
양방향 연관관계에서는 외래 키를 가진 주인 엔티티에서만 insert/update가 가능하므로, 항상 주인 쪽에서 값을 설정해야 DB에 반영된다.
✅ 예시
🚀 1:N (일대다) 연관관계
- 한 개체가 여러 개체와 관계를 맺는 구조 (예: 하나의 회원이 여러 개의 주문을 할 수 있음)
일대다 단방향
- 하나의 엔티티가 여러 엔티티를 참조하지만, 반대 방향에서는 참조하지 않음
- 참조 주체(보통 부모 엔티티)에서만 관계를 설정하고, 상대방(자식 엔티티)은 모름
@Entity
public class Member {
@Id @GeneratedValue
private Long id;
private String name;
@OneToMany
@JoinColumn(name = "member_id") // FK가 Order 테이블에 생성됨
private List<Order> orders = new ArrayList<>();
}
@Entity
public class Order {
@Id @GeneratedValue
private Long id;
private String productName;
}
- 여기서 Order는 Member를 모름 → 단방향 관계
❗️ @JoinColumn 없으면 중간 테이블이 생성되므로 주의!
일대다 단방향은 단순한 구조에서 빠르게 관계 설정 가능하므로, "정말 단순한 경우에만" 사용이 권장한다.
일대다 양방향
- 양쪽 엔티티가 서로를 참조한다.
- 주로 자식 엔티티가 연관관계의 주인이 되고, 부모는 읽기 전용으로 관계를 관리한다.
@Entity
public class Member {
@Id @GeneratedValue
private Long id;
private String name;
@OneToMany(mappedBy = "member") // 읽기 전용
private List<Order> orders = new ArrayList<>();
}
@Entity
public class Order {
@Id @GeneratedValue
private Long id;
private String productName;
@ManyToOne
@JoinColumn(name = "member_id") // FK 설정
private Member member;
}
- Order가 연관관계의 주인
- mappedBy는 연관관계의 주인이 아님을 명시한다.
예: 회원(Member)과 주문(Order)
단방향일 경우
- 회원 입장: 내 주문 목록을 조회할 수 있음
- 주문 입장: 누가 주문했는지 알 수 없음
양방향일 경우
- 회원 입장: 내 주문 목록을 조회할 수 있음
- 주문 입장: 어떤 회원이 주문했는지 알 수 있음
🚀 M:N (다대다) 연관관계
- 여러 개체가 서로 다수와 관계를 가지는 구조 (Student가 여러 Course를 수강하고, Course도 여러 Student를 가짐)
JPA는 다대다 관계를 직접 지원하나, 중간 테이블이 자동 생성된다.
중간 테이블이 JPA 내부에 숨겨져있어, 예상하지 못한 SQL이 발생할 수 있다. (성능, 쿼리 튜닝 어려움)
그러므로 유지보수와 유연성을 위해 중간 엔티티를 만들어 다대일/일대다로 풀어내는 걸 권장한다.
🚀 1:1 (일대일) 연관관계
- 한 개체가 다른 하나의 개체와 1:1로 매칭된다(User와 UserProfile)
외래 키는 아무 쪽에나 둘 수 있으나, 외래 키를 가진 쪽이 주인이다.
실무에서는 접근이 잦은 쪽에 외래 키를 둔다.
1:1 단방향 연관관계
- 한 쪽 엔티티에서만 참조(연관)를 가짐
- 예: Person → Passport 로만 접근 가능하고, 반대 방향은 불가능
@Entity
public class Person {
@Id
@GeneratedValue
private Long id;
private String name;
@OneToOne
@JoinColumn(name = "passport_id") // 외래키를 Person 테이블에 저장
private Passport passport;
}
@Entity
public class Passport {
@Id
@GeneratedValue
private Long id;
private String number;
}
- 외래키는 Person 테이블에 생성됨
- Passport에서 Person으로 접근 불가능하다.
1:1 양방향 연관관계
- 양쪽 엔티티 모두 서로 참조함
- 예: Person → Passport, Passport → Person
@Entity
public class Person {
@Id
@GeneratedValue
private Long id;
private String name;
@OneToOne
@JoinColumn(name = "passport_id")
private Passport passport;
}
@Entity
public class Passport {
@Id
@GeneratedValue
private Long id;
private String number;
@OneToOne(mappedBy = "passport") // 연관관계의 주인은 Person
private Person person;
}
- 외래키는 여전히 Person 테이블에 있음
- 양쪽 엔티티에서 서로 접근 가능
언제 어떤 방향을 쓸까?
상황 | 추천 방향 |
데이터 흐름이 명확하고 단방향 탐색만 필요 | 단방향 |
양방향 탐색이 필요한 비즈니스 로직 존재 | 양방향 |
연관 객체를 자주 조회하거나 UI에서 필요한 경우 | 양방향 |
데이터 수정/저장이 중심일 경우 | 단방향으로 시작 후 필요 시 확장 |
'Spring' 카테고리의 다른 글
Spring - 심화 주차 과제 세션 (2) | 2025.04.21 |
---|---|
Early Return 패턴 (1) | 2025.04.17 |
HttpMessageConverter (1) | 2025.04.15 |
뉴스피드 프로젝트 트러블 슈팅 (4) | 2025.04.14 |
JPQL이란? (@Query) (1) | 2025.04.10 |