티스토리 뷰
| 연관관계 매핑
객체의 참조와 테이블의 외래 키를 매핑
방향 (Direction) : 단방향, 양방향
방향은 객체관계에만 존재하고 테이블 관계는 항상 양방향
다중성 (Multiplicity) : 다대일, 일대다, 일대일, 다대다
연관관계의 주인 (owner)
|| 단방향 연관관계
객체 연관관계 : 단방향 관계
Member |
Team |
id Team team username |
id name |
테이블 연관관계 : 양방향 관계
Member | Team |
id Team team username | id name List members |
ㅇ 객체 연관관계 vs 테이블 연관관계
- 객체는 참조(주소)로 연관관계
ㄴ 연관 데이터 조회 시 .get() (참조) 사용 => 단방향
ㄴ 객체 그래프 탐색
- 테이블은 외래 키로 연관관계
ㄴ 연관 데이터 조회 시 JOIN 사용 => 양방향
* 객체를 양방향으로 참조하려면 단방향 연관관계를 2개 만들어야 함.
ㅇ 단방향 연관관계 매핑
> 회원 엔티티
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | @Entity public class Member { @Id @Column(name = "MEMBER_ID") private String id; private String username; @ManyToOne @JoinColumn(name="TEAM_ID") private Team team; // ... } | cs |
> 팀 엔티티
1 2 3 4 5 6 7 8 9 10 | @Entity public class Team { @Id @Column(name = "TEAM_ID") private String id; private String name; // ... } | cs |
@ManyToOne : 다대일(N:1) 관계 매핑 정보
연관관계 매핑 시 다중성 어노테이션은 필수
@JoinColumn(name="TEAM_ID") : 외래 키 매핑 (생량 가능)
name 속성에는 매핑할 외래 키 이름 지정
||| JoinColumn
외래 키 매핑 시 사용
> 속성
name : 매핑할 외래 키 이름
default. [필드명]_[참조하는 테이블의 기본키 컬럼명]
referencedColumnName : 외래 키가 참조하는 대상 테이블의 컬럼명
default. 참조하는 테이블의 기본 키 컬럼명
foreignKey (DDL) : 외래 키 제약조건을 직접 지정 (테이블 생성시에만 사용)
unique : @Column 속성과 동일
nullable
insertable
updatable
columnDefinition
table
* @JoinColumn 생략 시 외래 키를 찾을 때 기본 전략을 사용
[필드명]_[참조하는 테이블의 컬럼명]
||| ManyToOne
다대일 관계에서 사용
> 속성
optional : false 설정 시 연관된 엔티티가 항상 있어야 함. (default. true)
- EAGER 설정의 조인 전략
@ManyToOne, @OneToOne
- (optional = false) : 내부 조인
- (optional = true) : 외부 조인
@OneToMany, @ManyToMany
- (optional = false) : 외부 조인
- (optional = true) : 외부 조인
fetch : global fetch 전략 설정
@ManyToOne, @OneToOne(fetch = FetchType.EAGER) "즉시 로딩"
- 엔티티를 조회할 때 연관된 엔티티도 함께 조회
- 연관된 엔티티를 즉시 조회, hibernate는 가능하면 SQL 조인을 사용해서 한 번에 조회
- 객체가 계속 연결되어있을 경우 무한루프로 stack overflow 가능성..
@OneToMany, ManyToMany(fetch = FetchType.LAZY) "지연 로딩"
- 연관된 엔티티를 프록시로 조회, 프록시를 실제 사용할 때 초기화하면서 데이터베이스 조회
- 프록시 객체 : 지연 로딩 기능을 위해 실제 엔티티 객체 대신 데이터베이스 조회를 지연할 수 있는 가짜 객체
cascade : 영속성 전이 기능 사용
@OneToMany(mappedBy = "parent", cascade = CascadeType.PERSIST)
- 부모를 영속화할 때 연관된 자식들도 함께 영속화
- 부모 엔티티를 저장할 때 자식 엔티티도 함께 저장
, cascade = CascadeType.REMOVE
- 부모 엔티티만 삭제하면 연관된 자식 엔티티도 함께 삭제
- CasecadeType 의 다양한 옵션
ALL, // 모두 적용
PERSIST, // 영속
MERGE, // 병합
REMOVE, // 삭제
REFRESH,
DETACH
orphanRemoval : 부모 엔티티의 컬렉션에서 자식 엔티티의 참조만 제거하면 자식 엔티티가 자동으로 삭제(true)
- 참조하는 곳이 하나일 때만 사용 --> @OneToOne, @OneToMany
- CascadeType.Remove 설정과 동일
* cascadeType.All + orphanRemoval = true 일 경우, 부모 엔티티를 통해서 자식의 생명주기를 관리할 수 있음.
- 자식을 저장하려면 부모에 등록(CASECADE)
- 자식을 삭제하려면 부모에서 제거(removeObject)
1 2 3 4 5 | @OneToMany private List<Member> members; // 제네릭으로 타입 정보를 알 수 있음 @OneToMany(targetEntity=Member.class) private List<Member> members; // 제네릭이 없으면 타입 정보를 알 수 없음 | cs |
|| 양방향 연관관계
단방향 연관관계에서 양방향 연관관계를 만들기 위해
객체에서는 컬렉션을 사용해준다.
Member | Team |
id Team team username | id name List members |
데이터베이스 테이블은 외래 키 하나로 양방향 조회가 가능하므로
추가 내용이 없음
1 2 3 4 5 6 7 8 9 | @Id @Column(name = "MEMBER_ID") private String id; private String username; @ManyToOne @JoinColumn(name="TEAM_ID") private Team team; | cs |
ㅇ 양방향 연관관계 매핑
> 회원 엔티티
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | @Entity public class Member { @Id @Column(name = "MEMBER_ID") private String id; private String username; @ManyToOne @JoinColumn(name="TEAM_ID") private Team team; // 연관관계 설정 public void setTeam(Team team) { // 기존 팀과 관계를 제거 if (this.team != null) { this.team.getMembers().remove(this); } this.team = team; team.getMembers().add(this); } // ... } | cs |
> 팀 엔티티
1 2 3 4 5 6 7 8 9 10 11 12 13 | @Entity public class Team { @Id @Column(name = "TEAM_ID") private String id; private String name; @OneToMany(mappedBy = "team") private List<Member> members = new ArrayList<Member>(); // ... } | cs |
@OneToMany 의 mappedBy 속성은 양방향 매핑일 때 사용,
반대쪽 매핑의 필드 이름값으로 설정
|| 연관관계의 주인
객체에서의 연관관계는 "서로 다른 단방향 연관관계 2개" 와 같다.
단, 테이블은 외래 키 하나로 두 테이블의 연관관계를 관리한다.
엔티티를 양방향 연관관계로 설정하면 객체의 참조는 둘인데 외래 키는 하나가 되므로,
둘 사이에 차이가 발생한다.
=> 이러한 차이를 JPA에서는 두 객체 연관관계 중 하나를 정해서, 테이블의 외래키를 연관관계의 주인으로 관리
> 방향향 매핑의 규칙 : 연관관계의 주인
- 두 연관관계 중 하나의 연관관계의 주인으로 정해야 함
- 연관관계의 주인만이 데이터베이스 연관관계와 매핑되고 외래 키를 관리(등록, 수정, 삭제)할 수 있음
- 주인이 아닌 쪽은 읽기만 가능
- 연관관계 주인은 mappedBy 속성으로 정해줌
* 주인은 mappedBy 속성을 사용하지 않음
* 주인이 아니면 mappedBy 속성을 사용해서 속성의 값으로 연관관계의 주인을 지정해주어야 함
- 연관관계의 주인을 정한다는 것은 "외래 키 관리자를 선택하는 것"
ㄴ 외래키(FK) 가 있는 테이블 객체가 연관관계의 주인
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | @Entity public class Team { @Id @Column(name = "TEAM_ID") private String id; private String name; @OneToMany(mappedBy = "team") // 연관관계의 주인이 아님 // 연관관계의 주인은 Member.team private List<Member> members = new ArrayList<Member>(); // ... } | cs |
+
데이터베이스 테이블의 다대일, 일대다 관계에서는 항상 다 쪽이 외래 키를 가짐.
다 쪽인 @ManyToOne은 항상 연관관계의 주인이 되므로 mappedBy 설정이 불가 !
출처 : 자바 ORM 표준 JPA 프로그래밍
'Books' 카테고리의 다른 글
[JPA] 고급 매핑(상속관계, 복합키, 식별/비식별, 조인 테이블) (0) | 2020.12.21 |
---|---|
[JPA] 다양한 연관관계 매핑 (0) | 2020.12.21 |
[JPA] 엔티티와 매핑. @Entity, @Table, @Id, @Column.. (0) | 2020.12.18 |
[JPA] 영속성(persistence)이란? (0) | 2020.12.18 |
[JPA] JPA(Java Persistence API)가 뭐지!? (0) | 2020.12.18 |