백엔드

[스프링부트] 복합키 중 자동증가하는값 (ID) 지정 방법: @GeneratedValue.SEQUENCE

KyuminKim 2024. 11. 7. 22:49

 

결론

복합키 중 자동증가하는 값(ID)이 있으면

@GeneratedValue(strategy = GenerationType.SEQUENCE, generator="gen1")

이렇게 SEQUENCE 타입을 써야 한다 !!

(GenerationType.IDENTITY로 지정 x)

 


문제발견

프로젝트를 진행하며 스프링부트로 백엔드를 구현하고 있었다.

 

(ID) (AnotherKey)

 

2개를 엮어 복합키로 사용하고자 한다!

 

그런데

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "memberId", nullable = false)
Long memberId;

 

Identity generation isn't supported for composite ids: ID generation이 복합키 지원 x

Identity Generation이 복합키를 지원하지 않는다!

 


해결방법

public class Member extends BaseTimeEntity {
    @SequenceGenerator( // 제너레이터 정의
            name = "gen1", // JPA에서 사용할 제너레이터 이름
            sequenceName = "gen1", // DB 시퀀스 이름
            allocationSize = 1 // 증가 간격
    )

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator="gen1") // 제너레이터(gen1) 연결
    @Column(name = "ID", nullable = false)
    Long memberId;

    @Id
    @Column(name = "AnotherKey", nullable = false)
    String anotherKey;

ID값 생성 방식을 SEQUENCE로 바꿔줬다!

 


왜 되는가?

@GeneratedValue의 키본키 생성 방식

IDENTITY 기본키 생성을 데이터베이스에 위임  
SEQUENCE 기본키 생성을 시퀀스에서 담당
(@SequenceGenerator시퀀스 생성, 매핑 필요)
 
TABLE 기본키 생성을 테이블에서 담당
(@TablleGenerator로 테이블 생성, 매핑 필요)
 
AUTO (기본) IDENTITY, SEQUENCE, TABLE 중 하나 자동선택  

 


Identity 의 키 생성 방식

 

1.  Database에 INSERT할 데이터를 먼저 넣음 (키는 NULL)

데이터
NULL (넣을 데이터값)

현재 데이터베이스

 

🙋‍♀️ 키는 알아서 DB에서 만들어줘~

(키 생성은 DB에 일임)

 

 

 

2.  엔티티영속성 컨텍스트로 등록 시 INSERT쿼리 날림

🙋‍♀️이때, DB에 조회해 키를 가져옴 (DB에서 생성한 키)

데이터
NULL이 아닌값 (넣을 데이터값)

현재 데이터베이스

 

이때, 복합키의 경우에는,

즉 예를 들어

ID 다른 키 값
1 ABCD

 

라고 한다면,

스프링부트는 1, ABCD 중에 어떤 게 ID값인지 모른다.

(스프링부트 구현 상 그렇게 해둔 듯)

 

그래서 INSERT 쿼리를 날릴 때 ID를 채우지 못하고 실패하는 것이다.

 


 

Sequence 의 키 생성 방식

Oracle, PostgreSQL, DB2, D2 DB에서 지원하는 전략인 Sequence의 경우

 

연속 숫자를 생성하도록 Sequence를 생성하고,

이것을 이용해 ID를 생성하도록 하는 방식이다

 

public class Member extends BaseTimeEntity {
    @SequenceGenerator( // 제너레이터 정의
            name = "gen1", // JPA에서 사용할 제너레이터 이름
            sequenceName = "gen1", // DB 시퀀스 이름
            allocationSize = 1 // 증가 간격
    )

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator="gen1") // 제너레이터(gen1) 연결
    @Column(name = "ID", nullable = false)
    Long memberId;

나의 경우,

1씩 증가하는 sequence를 생성하고

이를 ID 생성 방식에 적용한 것이다

 

참고로 

@SequenceGenerator로 만든 Sequence

MINVALUE, MAXVALUE, NOCYCLE, START WITH, INCREASE 등 다양한 옵션을 사용할 수 있다

(더 많은 option에 대한 정보는 이 글에서 볼 수 있다)

 

 

 


참고

- @Generated 기본키 생성 방식 https://velog.io/@tritny6516/JPA-기본키Primary-Key-매핑-Id-GeneratedValue

- IDENTITY 기본키 생성 방식 https://gmlwjd9405.github.io/2019/08/12/primary-key-mapping.html#google_vignette