JPA에서 @GeneratedValue(strategy = GenerationType.IDENTITY)를 사용하면 기본 키(ID)를 자동 증가(AUTO_INCREMENT)하도록 설정된다.
MySQL에서는 IDENTITY 전략을 사용하면 JPA가 AUTO_INCREMENT 속성을 추가하며 알아서 작동한다.
PostgreSQL에서는 IDENTITY 전략을 사용하더라도 SERIAL 또는 IDENTITY를 사용해야한다.
MySQL만 쓰다가 PostgreSQL 로 넘어오면서 생긴 시행착오와 공부
목차
1. JPA의 기본키 생성전략
2. PostgreSQL 에서 IDENTITY 전략 사용하려면
3. PostgreSQL 에서 SEQUENCE 전략 사용하려면
1. JPA의 기본키 생성전략
JPA의 @GeneratedValue 전략은 다음과 같다.
IDENTITY | DB의 AUTO_INCREMENT 사용 (MySQL, PostgreSQL SERIAL) |
SEQUENCE | DB의 Sequence 사용 (nextval(), PostgreSQL, Oracle) |
AUTO | DB에 맞게 자동 선택 |
TABLE | 키 값을 저장하는 별도 테이블을 사용 |
이는 데이터베이스의 자동 증가 기능(AUTO_INCREMENT, SERIAL, IDENTITY 등)을 직접 활용하는 방식이다.
즉, JPA가 MYSQL 에서는 어플리케이션이 실행될 때 해당 주키에 AUTO_INCREMENT 속성을 부여한다.
// MySQL
INSERT INTO users (phone_number, password, created_at) VALUES ('01012345678', 'password123', NOW());
SELECT LAST_INSERT_ID(); -- 자동 증가된 ID 값을 가져옴
// PostgreSQL
INSERT INTO users (phone_number, password, created_at) VALUES ('01012345678', 'password123', NOW()) RETURNING id;
실제 쿼리문을 살펴보면, IDENTITY 전략에서는 JPA는 후에 Create 관련 쿼리가 들어왔을 때 영속성 컨텍스트에 엔티티를 등록하고, DB에 INSERT 쿼리를 먼저실행하여 생성된 ID 값을 가져오며, 다른 전략에서는 JPA가 flush 될때까지 INSERT 를 미루다가 persist() 할 때 INSERT를 실행한다.
GeneratedValue 를 실행하면 최종적으로 JPA 가 위와 같은 INSERT 문을 날리게 된다
- IDENTITY → 간단한 경우 추천
- SEQUENCE → 대규모 트랜잭션에서 성능 최적화 가능
- AUTO -> 여러 DB를 지원해야하는 경우
- TABLE -> 거의 사용하지 않음
한편, PostgreSQL 에서는 테이블에 SERIAL을 미리 명시해야 자동 증가된다는 차이가 있다!
2. PostgreSQL 에서 IDENTITY 전략 사용하려면
PostgreSQL에서는 IDENTITY 로 자동증가되는 기본키를 만들때 SERIAL 혹은 IDENTITY를 사용한다.
// MySQL
CREATE TABLE users (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
);
// PostgreSQL
CREATE TABLE users (
id SERIAL PRIMARY KEY, -- MySQL의 AUTO_INCREMENT와 같은 역할
);
// PostgreSQL 10 이상에서는 IDENTITY 도 가능 (표준 SQL 방식의 자동증가 기능이라고함)
CREATE TABLE users (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
);
SERIAL : 내부적으로 시퀀스를 생성하여 nextval()을 사용해서 자동 증가
IDENTITY : PostgreSQL 10부터 추가된 표준 SQL 방식의 자동 증가 기능
SERIAL 을 넣으면 자동으로 users_id_seq라는 시퀀스를 만들고 id 컬럼의 기본값을 nextval('users_id_seq')로 설정한다
SERIAL은 별도의 시퀀스를 만드는 반면, IDENTITY는 내부적으로 시퀀스를 관리한다
즉 SERIAL 은 데이터 타입이 아니라 AUTO_INCREMENT 같은 '속성' 이다.
다만 내부적으로 INTEGER 데이터타입을 포함하고있어서 별도로 타입을 명시하지 않는다.
(BIGSERIAL 을 사용하면 자동으로 BIGINT 타입이 됨)
3. PostgreSQL 에서 SEQUENCE 전략 사용하려면
혹은 기본키 전략을 아예 SEQUENCE 로 진행할 수도 있다.
GenerationType.SEQUENCE는 JPA가 직접 명시적으로 시퀀스를 사용하도록 설정하는 것
@Entity
public class User {
@Id
// 시퀀스를 사용하여 ID를 생성
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_seq")
// "users_id_seq" 시퀀스를 사용하도록 설정
@SequenceGenerator(name = "user_seq", sequenceName = "users_id_seq", allocationSize = 1)
private Long id;
}
위 코드는 PostgreSQL에서 "users_id_seq"라는 시퀀스를 사용하여 ID를 자동 증가시키겠다는 뜻이다.
이 설정을 하면 JPA가 다음과 같은 쿼리를 실행한다: SELECT nextval('users_id_seq');
- 기본적으로 Hibernate는 allocationSize = 50을 사용해서 한 번에 50개씩 미리 가져온다.
- allocationSize = 1을 설정하면 한 번씩 증가하도록 설정하는 것이다.
BIGSERIAL과 BIGINT + SEQUENCE의 차이
id SERIAL PRIMARY KEY | 자동 증가하는 INTEGER 타입 컬럼 | CREATE SEQUENCE + DEFAULT nextval(...) |
id BIGSERIAL PRIMARY KEY | 자동 증가하는 BIGINT 타입 컬럼 | CREATE SEQUENCE + DEFAULT nextval(...) |
id BIGINT PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY | PostgreSQL 표준 IDENTITY 컬럼 | 내부적으로 시퀀스 관리 |
id BIGINT PRIMARY KEY + SEQUENCE | 시퀀스를 명시적으로 생성 후 연결 | 직접 시퀀스를 관리해야 함 |
DDL-AUTO
- ddl-auto=create 또는 create-drop이면 JPA가 새 테이블을 만들 때 SERIAL을 자동 생성함.
- @GeneratedValue(strategy = GenerationType.IDENTITY)를 사용하면 PostgreSQL에서 SERIAL이 포함된 DDL을 생성함.
- ddl-auto=update는 기존 테이블을 변경하지 않음.
- 즉, id BIGINT PRIMARY KEY라고 이미 존재하면, JPA가 SERIAL을 추가로 설정하지 않음.
- 자동 증가 기능이 없는 상태로 남아있음.
- 변경하려면 수동으로 ALTER TABLE 해야 함.
ALTER COLUMN id SET DEFAULT nextval('users_id_seq'::regclass);은 id 컬럼이 시퀀스를 사용하도록 설정하는 쿼리
users_id_seq라는 시퀀스를 사용하여 id 값을 자동 증가
기존 flyway migration .sql 파일에 위의 쿼리문 삽입해서 해결!
'[개발일지] > CS 스터디 플랫폼' 카테고리의 다른 글
15장. 요청 본문 로깅 어디서 하지? 또 어떤 로그를 찍어놓을까 Filter Interceptor AOP (1) | 2025.03.29 |
---|---|
14장. DB에 물리적 FK 걸지마라. 조회가 빈번하면 인덱싱걸어라. (0) | 2025.03.27 |
12장. IntelliJ가 해주는 역할이 뭐였을까. Cursor AI로 넘어오면서 생긴 일들 (=Cursor 쓰면 새로운 디펜던시 반영 어떻게 (0) | 2025.03.20 |
11장. 상태관리 라이브러리 Context API 말고 다른거 쓰자. Redux? Zustand? (0) | 2025.02.28 |
10장. 운영환경에서 시크릿 파일 관리 노하우 (0) | 2025.02.11 |