김영한님이 지음, [자바 ORM 표준 JPA 프로그래밍] 책을 읽고 정리한 필기입니다.📢
일대다
- 일대다 관계는 다대일 관계의 반대 방향이다.
- 일대다 관계는 엔티티를 하나 이상 참조할 수 있으므로 컬렉션(
Collection
,List
,Set
,Map
) 중 하나를 사용해야 한다.
일대다 단방향[1:N]
하나의 팀은 여러 회원을 참조할 수 있는데 팀은 회원들을 참조하지만 반대로 회원은 팀을 참조하지 않는 경우 : 일대다
일대다 단방향
- 보통 자신이 매핑한 테이블의 외래 키를 관리하는데, 이 매핑은 반대쪽 테이블에 있는 외래 키를 관리하여 특이한 모습이 나타남
@JoinColumn
을 명시해야 함, 그렇지 않으면 JPA는 연결 테이블을 중간에 두고 연관관계를 관리하는 조인 테이블 전략을 사용
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Entity
public class Team{
@Id @GeneratedValue
@Column(name = "TEAM_ID")
private Long id;
private String name;
@OneToMany
@JoinColumn(name = "TEAM_ID") // MEMBER 테이블의 TEAM_ID (FK)
private List<Memeber> members = new ArrayList<Member>();
//Getter, Setter ...
}
1
2
3
4
5
6
7
8
9
10
@Entity
public class Member{
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
private String username;
//Getter, Setter ...
}
단점
매핑한 객체가 관리하는 외래 키가 다른 테이블에 존재하기 때문에 연관관계 처리를 위한 **추가 UPDATE SQL이 실행 됨**
1
2
3
4
5
6
7
8
9
10
11
12
13
public static void testSave(EntityManager em){
Member member1 = new Member("member1", "회원1");
Member member2 = new Member("member2", "회원2");
Team team1 = new Team("team1", "팀1");
team1.getMembers().add(member1);
team1.getMembers().add(member2);
em.persist(member1);//INSERT-member1
em.persist(member2);//INSERT-member2
em.persist(team1); //INSERT-team1, UPDATE-member1.fk,
//UPDATE-member2.fk
}
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
26
27
28
29
30
31
32
33
34
35
36
37
38
Hibernate:
/* insert org.example.Member
*/ insert
into
Member
(age, createdDate, description, lastModifiedDate, roleType, NAME, MEMBER_ID)
values
(?, ?, ?, ?, ?, ?, ?)
Hibernate:
/* insert org.example.Member
*/ insert
into
Member
(age, createdDate, description, lastModifiedDate, roleType, NAME, MEMBER_ID)
values
(?, ?, ?, ?, ?, ?, ?)
Hibernate:
/* insert org.example.Team
*/ insert
into
Team
(name, TEAM_ID)
values
(?, ?)
Hibernate:
/* create one-to-many row org.example.Team.members */ update
Member
set
TEAM_ID=?
where
MEMBER_ID=?
Hibernate:
/* create one-to-many row org.example.Team.members */ update
Member
set
TEAM_ID=?
where
MEMBER_ID=?
Member
엔티티는Team
엔티티를 모르고, 연관관계에 대한 정보는Team
엔티티의members
가 관리하므로Member
엔티티를 저장할 때는 MEMBER 테이블의 TEAM_ID 외래 키에는 아무 값도 저장되지 않음Team
엔티티를 저장할 때Team.members
의 참조 값을 확인해서 회원 테이블의 있는 TEAM_ID 외래 키를 업데이트- 일대다 단방향 매핑보다는 다대일 양방향 매핑을 사용해야 함
- 성능 문제도 있고 관리 포인트도 늘어 남
- 매핑 테이블의 모양또한 완전히 동일하고 엔티티만 약간 수정 해당 문제를 해결할 수 있는 다대일 양방향 매핑을 사용 권장
일대다 양방향[1:N, N:1]
- 일대다 양방향은 존재하지 않음
@OneToMany
는 연관관계의 주인이 될 수 없음- 관계형 데이터베이스 특성상 일대다, 다대일 관계는 항상 다 쪽에 외래 키 존재하기 때문에
@OneToMany
,@ManyToOne
둘 중에 연관관계의 주인은 항상 다 쪽인@ManyToOne
을 사용 - 때문에
@ManyToOne
에는mappedBy
속성이 존재하지 않음
그럼에도 양방향을 구현해야 할 경우엔 다대일 단방향 매핑을 읽기 전용으로 추가하면 가능, But. 일대다 단방향 매핑이 가지는 단점은 해결 불가능
일대다 양방향
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Entity
public class Team {
@Id @GeneratedValue
@Column(name = "TEAM_ID")
private Long id;
private String name;
@OneToMany
@JoinColumn(name = "TEAM_ID")
private List<Member> members = new ArrayList<Member>();
//Getter, Setter ...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
@Entity
public class Member {
@Id @generatedValue
@Column(name = "MEMBER_ID")
private Long id;
private String username;
@ManyToOne
@JoinColumn(name = "TEAM_ID", insertable = false, updatable = false)
private Team team;
//Getter, Setter ...
}
- 일대다 단방향 매핑과 같은 TEAM_ID 외래 키 컬럼을 매핑했지만 이렇게 되면 둘 다 같은 키를 관리하므로 문제 발생 가능
- 다대일 쪽은
insertable = false
,updatable = false
로 설정해서 읽기 전용으로 설정 해야 함
- 다대일 쪽은
댓글남기기