[JPA] 다양한 연관 관계 매핑 ( N:1 / 1:N / 1:1 / N:M )
* 정보전달의 목적이 아닌 개인 스터디 정리 글 입니다.
강의 : 인프런 <자바 ORM 표준 JPA 프로그래밍 기본편>
교육자 : 김영한
연관관계 매핑시 고려사항
- 다중성
- 다대일 : @ManyToOne
- 일대다 : @OneToMany
- 일대일 : @OneToOne
- 다대다 : @ManyYoMany
- 단방향, 양방향
- 테이블 : 외래키로 양쪽 조인 가능, 방향개념 없음
- 객체 : 참조용 필드가 있는 쪽으로만 참조 가능, 한쪽만 참조하면 단방향, 양쪽 서로 참조하면 양방향
- 연관관계의 주인
- 외래키를 관리하는 참조가 주인
- 주인의 반대편은 외래키에 영향을 주지않고 단순 조회만 가능
1. 다대일 (N:1)
: 외래키있는곳에 객체 참조 걸어주기
1-1. 다대일 단방향
- 가장 많이 사용하는 연관관계
- 다대일의 반대는 일대다
1-2. 다대일 양방향
- 외래키가 있는 쪽이 연관관계의 주인
- 양쪽을 서로 참조하도록 개발
- 반대쪽은 객체 추가만함. 읽기만 가능. 테이블 영향없음
2. 일대다 (1:N)
2-1. 일대다 단방향
- 1이 연관관계의 주인
- N쪽에 외래키가 있음
- 객체와 테이블의 차이 때문에 반대편 테이블의 외래키를 관리하는 구조
* 유의사항
- team을 insert 했는데 member의 update쿼리가 추가됨
- Joincolumn 어노테이션을 넣지않으면 하이버네이트가 중간테이블을 하나 추가함
일대다 단방향 매핑의 단점
- 엔티티가 관리하는 외래키가 다른(상대) 테이블에 있음
- 연관관계 관리를 위해 추가로 UPDATE SQL이 실행됨
=> 일대다 단방향 매핑보다 다대일 양방향 매핑을 사용을 권장
2-2. 일대다 양방향
: 공식적으로는 존재하지않고 야매로 속성을 넣어서 읽기전용으로 만들어야함
- @JoinColumn(insertable=false, updateable=false) 이와 같이 읽기 전용 필드를 사용해서 양방향 처럼 사용
=> 다대일 양방향 사용을 권장
3. 일대일 (1:1)
: 일대일 관계는 그 반대도 일대일
- 주 테이블이나 대상 테이블 중 외래키 선택 가능
- 외래키에 데이터베이스 유니크 제약조건 추가
3-1. 주 테이블에 외래키 단방향
- 다대일 단방향 매핑과 유사
3-2. 주 테이블에 외래키 양방향
- 다대일 양방향 매핑 처럼 외래키가 있는 곳이 연관관계의 주인
- 반대편은 mappedBy 적용
3-3. 대상 테이블에 외래키 단방향
- 단방향 관계는 JPA 지원하지 않음
- 양방향 관계는 지원
3-4. 대상 테이블에 외래키 양방향
- 일대일 주 테이블에 외래키 양방향과 매핑 방법이 같음 (테이블 반대로 뒤집는 차이)
* 장단점 정리
- 주 테이블에 외래키 : 객체지향 개발자 선호, JPA 매핑 편리
- 장점 : 주 테이블만 조회해도 대상 테이블에 데이터가 있는지 확인가능
- 단점 : 값이 없으면 외래키에 null허용
- 대상 테이블에 외래키 : 데이터베이스 개발자 선호 (테이블 변경할 변수가 적음)
- 장점 : 주 테이블과 대상 테이블을 일대일에서 일대다 관계로 변경할 때 테이블 구조 유지가능
- 단점 : 프록시 기능의 한계로 지연 로딩으로 설정해도 항상 즉시 로딩됨
4. 다대다(N:M)
: 관계형 데이터베이스는 정규화된 테이블 2개로 다대다 관계를 표현할 수 없음
- 연결 테이블을 추가해서 일대다, 다대일 관계로 풀어야함
- 객체는 컬렉션을 사용해서 객체 2개로 다대다 관계 가능
- @ManyToMany 사용, @JoinTable로 연결 테이블 지정
- 다대다 매핑 : 단방향, 양방향 가능
다대다 => 실무에서 쓰면 안된다 ?
이유
: 연결테이블이 필요한데 실무에서는 단순하게 연결만 하고 끝나지않음. ( 테이블에 계속 필요한 데이터가 추가될 수 있음 )
따라서 일대다, 다대일로 풀어서 사용할것. 중간테이블을 엔티티로 승격!
ex) Member와 Product 사이의 중간테이블 (Memeber_Product)을 Order 테이블로 바꾸어 엔티티로 만들기
* 주요 어노테이션 속성 설명
@JoinColumn : 외래키 매핑시 사용
속성 | 설명 | 기본값 |
name | 매핑할 외래 키 이름 | 필드명 + _ + 참조하는 테 이블의 기본 키 컬럼명 |
referencedColumnName | 외래 키가 참조하는 대상 테이블의 컬럼명 | 참조하는 테이블의 기본 키 컬럼명 |
foreignKey(DDL) | 외래 키 제약조건을 직접 지정할 수 있다. 이 속성은 테이블을 생성할 때만 사용한다. | |
unique nullable insertable updatable columnDefinition table |
@Column의 속성과 같다. |
@ManyToOne : 다대일 관계 매핑
속성 | 설명 | 기본값 |
optional | false로 설정하면 연관된 엔티티가 항상 있어야 한다. | TRUE |
fetch | 글로벌 페치 전략을 설정한다. | - @ManyToOne=FetchType.EAGER - @OneToMany=FetchType.LAZY |
cascade | 영속성 전이 기능을 사용한다. | |
targetEntity | 연관된 엔티티의 타입 정보를 설정한다. 이 기능은 거 의 사용하지 않는다. 컬렉션을 사용해도 제네릭으로 타 입 정보를 알 수 있다. |
@OneToMany : 일대다 관계 매핑
속성 | 설명 | 기본값 |
mappedBy | 연관관계의 주인 필드를 선택한다. | |
fetch | 글로벌 페치 전략을 설정한다. | - @ManyToOne=FetchType.EAGER - @OneToMany=FetchType.LAZY |
cascade | 영속성 전이 기능을 사용한다. | |
targetEntity | 연관된 엔티티의 타입 정보를 설정한다. 이 기능은 거 의 사용하지 않는다. 컬렉션을 사용해도 제네릭으로 타 입 정보를 알 수 있다. |