JPA의 복합 키

..·2025년 12월 23일

finder

목록 보기
23/23

사용자의 로그를 쌓는 테이블에서 복합 키를 사용하다가 오류가 발생했는데, 이 과정에서 여러 가지를 알게 되어서 기록하게 됐다.

기존 구조

로그 테이블(MySQL)

사용자 로그 테이블은 Date(YYYY-MM-DD)를 사용하여 1개월 단위의 파티션을 생성한다.
MySQL에서는 파티션 키를 반드시 PK에 포함해야 한다.
따라서 log_idlog_date를 복합키로 사용한다.

JPA Entity

사용자 로그 테이블에 대한 모델을 작성할 때, 복합 키를 IdClass로 작성하여 사용한다. PK로 사용하는 컬럼에는 @Id를 추가한다.

...

// 복합 키 클래스
@IdClass(LogId.class)  
public class Log {

	@Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "log_id")
    private Long logId;

	@Id
	@Column(name = "log_date")
    private LocalDate logDate;

	...
}

문제 상황

복합 키와 GenerationType.IDENTITY의 충돌

JPA는 복합 키를 사용할 때, GenerationType.IDENTITY를 사용할 수 없다.
하지만 log_idAUTO INCREMENT하는 INT형 데이터이기 때문에 해당 설정을 필수로 사용해야 하는 상황이다.


문제의 원인

복합 키는 2개 이상의 컬럼으로 구성되어 있는데, 단일 컬럼처럼 자동 증가하는 값을 생성하는 DB의 매커니즘과 충돌한다.
JPA의 IDENTITY는 DB의 자동 증가에 의존하는데, 복합 키는 여러 필드 조합으로 고유성을 결정하기 때문에 GenerationType.IDENTITY 설정을 사용할 수 없다.

시도한 방법

1. MySQL에서 단일 PK를 사용하기

log_idauto_increment가 필수 요소라고 생각해서 복합 키에 IDENTITY 설정을 넣을 수 없다면, MySQL의 테이블 구조를 변경해야겠다고 생각했다.
다른 RDBMS에서는 파티션 키를 PK가 아닌 Unique Key로 사용할 수 있지만, MySQL에서는 파티션 키는 반드시 PK가 되어야 한다는 제약이 있다.
로그 데이터는 날짜별 관리가 필수라고 생각해서 날짜를 기준으로 파티션을 생성한 것이기 때문에, 파티션 또한 포기할 수 없는 구조라고 생각해서 결과적으로는 테이블 설정 변경을 포기했다.

2. 단일 ID로 변경

테이블 설정을 변경할 수 없으니, 모델에서 설정 변경이 필요하다.
JPA에서 복합 키를 사용하면서 AUTO INCREMENT를 사용하고 싶으면, 비즈니스 로직과 관계없는 ID 필드를 생성하여 대리 키로 사용할 수 있다.
하지만 조금 더 간단한 방법을 선택했다. MySQL의 키와 JPA의 식별자가 반드시 일치할 필요가 없다는 점을 이용하여, 모델에서 log_id만 PK로 사용하여 GenerationType.IDENTITY 설정을 유지하는 방법을 선택했다.

변경된 Log Entity


...

public class Log {

	@Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "log_id")
    private Long logId;

	@Column(name = "log_date")
    private LocalDate logDate;

	...
}

복합 키 클래스를 제거하고, log_id@Id로 사용하도록 수정했다.


JPA의 복합 키는 왜 IDENTITY를 사용할 수 없을까?

JPA는 객체와 데이터베이스를 연결하는 자바 표준 기술이고, 영속성 컨텍스트는 엔티티 객체들을 관리하는 논리적인 메모리 공간이다.
JPA는 엔티티 영속화를 위해 식별자 값을 알아야 하고, 식별자를 알아야 엔티티를 관리할 수 있다.
@GeneratedValue는 전체 식별자 값 생성을 담당하는데, 복합 키의 일부만 자동 생성되도록 설계되어 있지 않다. 또한 IDENTITY 설정은 DB INSERT 실행 후에 값을 알 수 있는데, 복합 키의 일부만 자동 생성되면 메모리 상의 엔티티는 완전한 식별자를 가지지 못한다.
따라서 JPA의 복합 키는 IDENTITY 설정을 사용할 수 없다.


마무리

JPA에서 복합 키를 사용한 적은 있지만 IDENTITY 설정을 적용한 @Id를 사용한 것은 처음이라 이런 문제가 있다는 것 또한 처음 알았다.
문제를 해결하는 과정에서 MySQL은 파티션 키를 반드시 PK에 포함해야 한다는 것, 하지만 다른 RDBMS에서는 Unique Key로 사용할 수 있다는 것, JPA와 영속성 컨텍스트에 대한 것, JPA에서 복합 키를 사용하면서 IDENTITY 설정을 위해 대체 키를 사용한다는 것을 알 수 있었다.

0개의 댓글