1. 소개
Spring Data JPA를 사용하다 보면, 단일 필드가 아닌 여러 개의 필드를 조합하여 기본 키(Primary Key)로 사용하는 복합 키(Composite Key) 를 설정해야 할 때가 있다.
JPA에서 복합 키를 매핑하는 방법은 크게 두 가지이다.
- @EmbeddedId + @Embeddable
- @IdClass
이번 글에서는 두 방법을 비교하고, 코드 예제를 통해 직접 실습할 수 있도록 정리해보겠다.
2. @EmbeddedId 방식 (추천 방식)
@EmbeddedId + @Embeddable
1. @Embeddable: 복합 키 클래스로 사용할 객체에 선언
2. @EmbeddedId: 엔티티에서 해당 복합 키를 기본 키로 사용
(1) 복합 키 정의 (OrderId 클래스)
import java.io.Serializable;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode
public class OrderId implements Serializable {
private Long orderId;
private Long productId;
public OrderId() {}
public OrderId(Long orderId, Long productId) {
this.orderId = orderId;
this.productId = productId;
}
}
- @Embeddable: 복합 키 클래스로 사용되며, 개별 엔티티가 아닌 다른 엔티티에 포함될 수 있음
- @EqualsAndHashCode: JPA에서 비교 연산을 정확히 수행하기 위해 필수
- Serializable 구현: JPA에서 복합 키 클래스로 사용하려면 Serializable을 구현해야 함
(2) 엔티티 정의 (Order 클래스)
import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Entity
@IdClass(OrderId.class)
@Getter
@Setter
@NoArgsConstructor
public class OrderEntity {
@Id
private Long orderId;
@Id
private Long productId;
private int quantity;
public OrderEntity(Long orderId, Long productId, int quantity) {
this.orderId = orderId;
this.productId = productId;
this.quantity = quantity;
}
}
- @EmbeddedId: 복합 키 클래스를 기본 키로 사용
- id 필드가 OrderId 객체이므로, 여러 개의 필드를 하나의 객체로 관리 가능
이 방식은 객체지향적인 설계를 유지할 수 있어 더 선호되는 방법
3. @IdClass 방식
@IdClass
1. 엔티티 클래스 내부에서 개별적으로 @Id를 선언
2. @IdClass를 통해 외부에서 해당 키가 어떤 필드로 구성되는지 명시
코드 예제: @IdClass를 사용한 복합 키 매핑
(1) 복합 키 정의 (OrderId 클래스)
import java.io.Serializable;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode
public class OrderId implements Serializable {
private Long orderId;
private Long productId;
public OrderId() {}
public OrderId(Long orderId, Long productId) {
this.orderId = orderId;
this.productId = productId;
}
}
- @EqualsAndHashCode: 복합 키 비교를 위해 반드시 필요
- Serializable 구현: 필수
(2) 엔티티 정의 (Order 클래스)
import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Entity
@IdClass(OrderId.class)
@Getter
@Setter
@NoArgsConstructor
public class OrderEntity {
@Id
private Long orderId;
@Id
private Long productId;
private int quantity;
public OrderEntity(Long orderId, Long productId, int quantity) {
this.orderId = orderId;
this.productId = productId;
this.quantity = quantity;
}
}
- @IdClass(OrderId.class): 복합 키를 사용한다고 명시
- 엔티티 내부에서 @Id 필드를 직접 선언해야 함
이 방식은 엔티티 필드 내에서 직접 ID를 선언해야 하므로, 비교적 덜 객체지향적
4. @EmbeddedId vs @IdClass 비교
설정 방식 | @EmbeddedId 필드에 복합 키 객체 사용 | 개별 @Id 필드를 엔티티에 선언 |
ID 클래스 | @Embeddable 사용 | @IdClass 사용 |
코드 구조 | 객체지향적으로 키를 하나의 객체로 관리 | SQL 테이블 구조와 유사 |
장점 | 코드 재사용성 높음, 유지보수 용이 | SQL 구조와 유사하여 직관적 |
단점 | JPA 외부 시스템과의 연동 시 다소 복잡할 수 있음 | 필드가 엔티티 내부에 있어 응집성 떨어짐 |
5. 정리
- JPA에서 복합 키를 사용하려면 @EmbeddedId 또는 @IdClass
- @EmbeddedId는 객체지향적인 방식으로 관리가 용이하고 유지보수가 쉬움.
- @IdClass는 SQL과 유사한 구조로 가독성이 좋지만, 코드 응집성이 떨어질 수 있음.
'Spring' 카테고리의 다른 글
[Spring] JPA Auditing 어노테이션 / @EnableJpaAuditing, @EntityListeners (0) | 2025.02.24 |
---|---|
[Spring] RowMapper란 ? (0) | 2024.05.12 |
[Spring] Entity 에 쓰이는 Annotation (0) | 2024.03.10 |
[Spring] Nginx와 Spring Server를 활용한 무중단 배포 (0) | 2024.01.29 |
[Spring] Nginx에 http 대신 https 적용하기 (0) | 2024.01.29 |