본 문서는 인프런의 자바 ORM 표준 JPA 프로그래밍 - 기본편 (김영한) 강의를 공부하며 작성한 개인 노트입니다.
연관관계 매핑시 고려사항 3가지
- 다중성 (예) 다대일, 일대다, 일대일, 다대다
- 단방향/양방향
- 테이블
- 외래키 하나로 양쪽 조인 가능
- 방향이라는 개념 X
- 객체
- 참조용 필드가 있는 쪽으로만 참조 가능
- 한쪽만 참조 > 단방향
- 양쪽이 참조 > 양방향
- 연관관계의 주인
- 테이블: 외래 키 하나로 두 테이블이 연관관계 맺음
- 객체: A > B와 B > A 해서 참조가 2곳
- 둘 중 테이블의 외래키를 관리할 곳은? 연관관계의 주인
- 주인의 반대편 - 단순 조회만 가능. 외래 키 관리 X
🦀 다대일 (N:1), @ManyToOne
- 연관관계의 주인 반대편에서 참조를 추가한다고 해서 테이블에 변화는 없음
- 외래키가 있는 쪽이 연관관계의 주인이다
🦐 일대다 (1:N), @OneToMany
일에서 다를 관리 (ex) 팀에서 멤버를 관리 > Team
클래스에 List<Member> members
필드
- 다 쪽에 외래키가 있음
- 객체와 테이플의 차이 > 일에서 반대편 테이블의 외래키를 관리하게 됨 > UPDATE 쿼리 추가적으로 생성
- @JoinColumn은 필수
- 없이는 조인 테이블 방식 사용 > 테이블 추가 > 성능/관리 애매함
public class Team {
...
@OneToMany
@JoinColumn(name = "TEAM_ID")
private List<Member> members = new ArrayList<>();
...
}
- MEMBER 테이블의 TEAM_ID (FK, 외래키)를 같이 업데이트하기 위해 update 쿼리가 나가야 하기 때문에 성능상 문제
- 테이블이 많아질 수록 관리가 어렵기 때문에 권장 X
- Member에 주인권한을 주는게 더 좋음 > 다대일 단방향 + 양방향 조합이 더 좋음
일대다 양방향

- 공식적으로 존재하지는 않음
@JoinColumn(insertable=false, updatable=false)
- 읽기 전용 모드로 양방향처럼 사용
- 다대일 양방향 사용하자
🦑 일대일 (1:1), @OneToOne

- 주/대상 테이블 중에 외래키 선택 가능
- 외래키가 있는 곳이 연관관계의 주인 & 반대편은 mappedBy 적용
- 외래 키에 디비 유니크(UNIQUE/UNI) 제약조건 추가
@OneToOne
@JoinColumn(name = "")
은 권장
대상 테이블에 외래키 단방향
Member가 주테이블인데 외래키는 Locker에 있을 경우
불가능함
대상 테이블에 외래키 양방향
가능은 함
주 테이블에 외래키 단방향
Member에 외래키가 있는게 성능상 유리함
- Member 테이블을 자주 select한다고 봤을 때 locker_id가 여기 있는 것이 수월함
- 하지만 Member 테이블에 null 값이 들어올 수 있어서 불편할 수는 있음
선호되는 방식
주 테이블에 외래키 양방향
정리
- 주 테이블에 외래 키
- 주 테이블에 외래키를 두고 대상 테이블을 찾음
- 객체지향
- JPA 매핑 관리
- 장점: 주 테이블만 조회해도 대상 테이블에 데이터가 있는지 확인 가능
- 단점: 값이 없으면 외래키에 null 값
- 대상 테이블에 외래 키
- 대상 테이블에 외래 키
- 디비
- 장점: 주 & 대상 테이블을 일대일에서 일대다 관계로 변경할 때 테이블 구조 유지
- 단점: 자연 로딩으로 설정해도 항상 즉시 로딩됨
🐡 다대다 (N:M), @ManyToMany
실무에서 사용 X
- 관계형 디비는 정규환 테이블 2개로 다대다를 표현할 수 없음
- 연결 테이블을 추가해서 일대다, 다대일 관계로 풀어내야함
- 객체는 컬렉션으로 객체 2개의 다대다 관계 가능
- 한계
- 실무에서 사용 불가
- 연결 테이블은 연결에서 끝나지 않음
- 다양한 데이터가 들어올 수도 있는데 중간테이블에는 정보 추가가 안됨
- 쿼리가 복잡해짐
- 해결
- 연결 테이블용 엔티티 추가 > 연결테이블을 엔티티로 승격
- @ManyToMany > @ManyToOne + @OneToMany
- 정 필요하면 제약조건 추가

🐙 실전 예제 3 - 다양한 연관관계 매핑
- 엔티티 배송 & 카테고리 추가
- 주문:배송 = 1:1
- 상품:카테고리 = N:M
- Delivery (+ DeliveryStatus enum) & Category 클래스 생성
@JoinColumn
외래 키 매핑시 사용
속성
name
- 매핑할 외래키 이름
- 기본값: 필드명 + _ + 참조하는 테이블의 기본키 컬럼명
referencedColumnName
- 외래키가 참조하는 대상 테이블의 컬럼명
foreignKey
(DDL) - 외래키 제약조건을 직접 지정
unique
, nullable
, insertable
, updatable
, columnDefinition
, table
- @Column 속성과 같음
@ManyToOne
다대일 관계 매핑
속성
optional
- false로 설정하면 연관된 엔티티가 항상 있어야함
fetch
- 글로벌 패치 전략 설정
- 기본값
@ManyToOne=FetchType.EAGER
@OneToMany=FetchType.LAZY
cascade
- 영속성 전이 기능 사용
targetEntity
- 연관된 엔티티의 타입 정보 설정
- 거의 사용X
- 컬렉션을 사용해도 제네릭으로 타입 정보 알 수 있음
@OneToMany
다대일 관계 매핑
속성
mappedBy
- 연관관계의 주인 필드 선택
fetch
- 글로벌 패치 전략 설정
@ManyToOne=FetchType.EAGER
@OneToMany=FetchType.LAZY
cascade
- 영속 전이 기능 사용
targetEntity
- 연관된 엔티티의 타입 정보 설정
- 거의 사용 X
- 컬렉션을 사용해도 제네릭으로 타입 정보 알 수 있음