복합키(Composite Key) vs 고유 Id
JPA에서 N:M 관계를 매핑할 때, 중간 테이블(연결 테이블)에 고유 ID(@Id)를 넣을 것인지, 복합 키(@EmbeddedId)를 사용할 것인지 고민하는 경우가 많다.
처음에는 "그냥 @Id를 넣고 auto_increment 하면 되지 않나?"라고 생각할 수 있지만, 이 방식은 데이터 무결성과 성능 문제를 초래할 수 있다.본 글에서는 복합 키(Composite Key)를 사용할 때의 장점과 @Id 방식이 가지는 문제점을 분석해보겠다.
N:M 관계에서 중간 테이블의 역할
- ProblemSet(문제지)와 Problem(문제)은 N:M 관계이다.
- 따라서 ProblemSetToProblem이라는 중간 테이블이 필요하다.
- 이때, 이 테이블의 고유 식별자(PK)를 어떻게 설정해야 할까?
- @Id(고유 ID를 생성하는 방식)
- @EmbeddedId(복합 키를 이용하는 방식)
고유 Id를 사용했을 경우?
@Entity
@Table(name = "problem_set_to_problem")
public class ProblemSetToProblem {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) // 자동 증가 ID
private Long id;
@ManyToOne
@JoinColumn(name = "problem_set_id", nullable = false)
private ProblemSet problemSet;
@ManyToOne
@JoinColumn(name = "problem_id", nullable = false)
private Problem problem;
}
이렇게 고유 Id를 사용할 경우에 문제점들이 존재한다.
(1) 데이터 무결성(Integrity) 문제
- problem_set_id, problem_id 조합이 중복 삽입될 수 있다.
INSERT INTO problem_set_to_problem (problem_set_id, problem_id) VALUES (1, 5);
INSERT INTO problem_set_to_problem (problem_set_id, problem_id) VALUES (1, 5); -- 중복 가능 ❌
(2) 쿼리의 복잡성 증가
- problem_set_id와 problem_id로 데이터를 조회하려면 WHERE 조건이 추가로 필요하다.
- 반면, @EmbeddedId를 사용하면 findById()로 간단하게 조회 가능하다.
(3) 비즈니스 로직 관점에서 의미 없는 ID
- 이 테이블은 "어떤 문제지가 어떤 문제를 포함하는가" 를 나타내는 역할만 한다.
- 하지만, id를 추가하면 문제지-문제 간의 관계가 아닌, 단순한 테이블 row 번호만을 가지게 된다.
- problem_set_id + problem_id 조합이 이 테이블의 진짜 고유 식별자가 되어야 한다.
복합 키(@EmbeddedId)를 사용하면 어떻게 해결될까?
@Entity
@Table(name = "problem_set_to_problem")
public class ProblemSetToProblem {
@EmbeddedId
private ProblemSetToProblemId id;
@ManyToOne
@MapsId("problemSetId")
@JoinColumn(name = "problem_set_id", nullable = false)
private ProblemSet problemSet;
@ManyToOne
@MapsId("problemId")
@JoinColumn(name = "problem_id", nullable = false)
private Problem problem;
}
@Embeddable
public class ProblemSetToProblemId implements Serializable {
private Long problemSetId;
private Long problemId;
}
복합키 방식의 장점
- 데이터 무결성 유지: 동일한 problem_set_id, problem_id 조합의 중복 입력 방지
- 더 쉬운 조회 가능: findById()로 복합 키 조회 가능
- 테이블 자체의 의미를 더 명확하게 표현
결론 - 언제 @EmbeddedId를 사용할까?
복합 키(@EmbeddedId)를 사용하는 것이 좋은 경우
- 연결 테이블(Bridge Table)에서 N:M 관계를 매핑할 때
- 테이블 자체가 특정 두 개의 외래 키 조합으로 유일성을 가져야 할 때
- 고유 ID가 의미 없는 경우 (단순히 row를 구분하기 위해 ID를 만드는 것이 비효율적일 때)
고유 ID(@Id)를 사용하는 것이 좋은 경우
- 테이블이 단순한 연결 테이블이 아니라 별도의 속성을 가질 때
- 예: StudentTest 같은 테이블에서 추가적인 score(점수) 같은 속성이 필요한 경우.
- 테이블이 독립적인 엔티티로 사용될 때
- 예: 단순한 N:M 관계가 아니라, 그 자체가 비즈니스 로직에서 중요한 역할을 할 경우.
'EduClass Project' 카테고리의 다른 글
[Project] 복합 키 적용 전후, MySQL 성능 차이 실험 - MySQLWorkBench (0) | 2025.03.25 |
---|---|
[Project] 학생 시험 채점 기능 개선 - DTO 활용으로 확장성 높이기 (0) | 2025.03.07 |
[Project] 불필요한 Entity 제거를 통한 데이터베이스 설계 최적화 – Test Entity를 없앤 이유 (0) | 2025.03.05 |
[Project] (4) API 구현(@RequestParam vs @PathVariable) (0) | 2025.02.07 |
[Project] (3) 프로젝트 시작(MVC 패턴, 디렉토리 구조) (1) | 2025.02.05 |