FK의 위치는 DB 설계 시에 매우 중요한 결정 사항이며, JPA 같은 ORM 환경에서는 객체 탐색, 연관관계 주인, 생명주기 등과도 깊게 된다.
User : UserStatususer_status.user_idChannel : Messagemessage.channel_idUser : BinaryContentUser.profile_idUser : Messagemessage.author_idChannel : ReadStatusread_status.channel_id| 관계 유형 | FK를 두는 위치 | 비고 |
|---|---|---|
| 종속 관계 | 종속된 테이블 | 생명주기 의존, CASCADE 설정 용이 |
| 참조 관계 | 참조하는 테이블 | 독립성 보장, 결합도 낮춤 |
| 1:N 관계 | N쪽 테이블 | 구조적으로 필수 |
=> FK는 어디에 있어도 상관없지만, 성능상의 이점이나 편의성을 위해 두면 좋은 곳이 존재한다!
User.getStatus()처럼 객체 탐색이 중요=> 그래서, FK는 종속성(UserStatus는 User에 종속)에 따라 user_status.user_id에 있지만, JPA에서는 User 엔티티에 UserStatus 필드를 선언해 user.getUserStatus()로 탐색하게끔 구현 가능! (UserStatus에서 User를 탐색하는 경우가 많다면, UserStatus에도 User를 추가하여 양방향 매핑 가능)
User -> UserStatus를 탐색하기 때문에 User에서도 UserStatus를 가지고,
JPA에서는 FK를 가진 쪽을 연관관계의 주인으로 하는것을 권장하기 때문에 UserStatus도 User를 가져서 연관관계를 맺음 (탐색하지 않더라도)
Message : BinaryContentmessage_attachments) 필요→ 반대로, 1:1이나 1:N 관계에서는 중간 테이블 없이 FK로 직접 연결하는 것이 일반적
| 개념 | 연관관계 주인 | 탐색 방향 |
|---|---|---|
| 의미 | FK를 실제로 관리하는 쪽 | 어느 쪽에서 참조할 수 있는지 (JPA 필드 선언 기준) |
| 결정 기준 | @JoinColumn이 선언된 쪽 | 필드가 선언된 쪽이 탐색 가능 |
@Entity
class ReadStatus {
@ManyToOne
@JoinColumn(name = "user_id") //연관관계의 주인 (FK 관리)
private User user;
}
@Entity
class User {
// 탐색은 불가능 (단방향)
}
→ 탐색은 ReadStatus → User만 가능, 연관관계 주인도 ReadStatus
@Entity
public class Member {
@ManyToOne
@JoinColumn(name = "team_id") // FK 소유자 = 연관관계의 주인
private Team team;
}
@Entity
public class Team {
@OneToMany(mappedBy = "team") // 연관관계의 주인이 아님
private List<Member> members = new ArrayList<>();
}
Team team = new Team();
Member member = new Member();
team.getMembers().add(member); // 비주인만 수정
em.persist(member); // member.team은 null
public void addMember(Member member) {
members.add(member); // team → member
member.setTeam(this); // member → team
}