JPA는 데이터베이스의 기본 키(Primary Key) 생성 전략을 지원하기 위해 다양한 옵션을 제공합니다. @GeneratedValue 어노테이션을 사용하여 엔티티의 @Id 필드에 키 생성 전략을 지정할 수 있습니다. 이 글에서는 각 전략의 동작 방식, 장단점, 그리고 실제 활용 사례를 다뤄보겠습니다.

JPA 키 매핑 전략 종류
AUTO 전략
AUTO 전략은 데이터베이스 방언(dialect)에 따라 적합한 키 생성 전략을 자동으로 선택합니다.
| MySQL | IDENTITY 전략 사용 |
| Oracle | SEQUENCE 전략 사용 |
| 범용 DB | TABLE 전략 사용 |
@Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id;
AUTO 전략의 장점
데이터베이스 독립성이 보장되어 있어, 데이터베이스가 바뀌어도 코드를 수정할 필요가 없으며 이러한 이점을 이용해 초기 개발시 설정이 간단하고 유연하기에 개발할 때 가장 많이 쓰입니다.
AUTO 전략의 단점
특정 DB에서는 비효율적인 전략이 선택될 수 있습니다.MySQL에서는 IDENTITY 전략이 선택되기 때문에 배치 처리 최적화가 어려우며 따로 시퀀스를 지원하는 Mysql을 사용하거나 혹은 순수 JDBC로 처리를 해야 하는데, 이후 자세히 설명하겠습니다.
SEQUENCE 전략
SEQUENCE는 데이터베이스의 시퀀스 객체를 사용하여 키를 미리 생성하는 개념으로 엔티티 객체를 persist() 호출 시 나오는 SELECT NEXTVAL('시퀀스명')를 통해 여러 개의 키를 미리 확보합니다. 즉 이로인해 다른 전략과는 달리 쓰기 지연이 가능하여 배치 최적화에 유리합니다. 무슨 말인지 헷갈리겠지만 아래의 글들을 보면 서서히 이해가 될 것입니다.
@SequenceGenerator(
name = "USER_SEQ_GENERATOR",
sequenceName = "USER_SEQ",
initialValue = 1,
allocationSize = 50
)
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "USER_SEQ_GENERATOR")
private Long id;
| name | JPA에서 사용할 시퀀스 이름입니다. |
| sequenceName | 실제 데이터베이스 시퀀스 객체 이름입니다. |
| initialValue | 시퀀스 시작값입니다. |
| allocationSize | JPA가 한 번에 미리 확보할 키 개수입니다. (기본값: 50) |
여기서 특히 allocationSize가 중요한 데, 매번 persist() 시 SELECT NEXTVAL('USER_SEQ')를 실행하면 성능이 저하됩니다. 하지만 allocationSize=50으로 설정하면 한 번의 쿼리로 50개의 키를 확보해 성능을 최적화가 가능해집니다. 하지만 명심해야 될 것은 "기본값이 50" 이라는 점입니다.
설정하지 않은 채 코드를 작성하다 보면 개발자와의 의도와는 다르게 기본 키가 매우 많아질 수도, 혹은 배치에 비해 부족해질 수도 있다는 것이기에 꼭 나에게 맞는 값으로 설정해야 합니다.
SEQUENCE 전략 동작 흐름
- em.persist(user) 호출
- JPA는 시퀀스를 통해 SELECT NEXTVAL('USER_SEQ')를 실행
- 여러 개의 키를 한 번에 확보 (예: 1~50)
- 확보한 키 중 첫 번째 키(1)를 user 엔티티에 할당
- 영속성 컨텍스트의 1차 캐시에 저장
- INSERT SQL은 트랜잭션 커밋 시 실행
SEQUENCE 전략은 키를 미리 확보하여 persist() 단계에선 AUTO 전략과는 달리 즉시 INSERT를 실행하지 않고, 쓰기 지연 전략이 가능합니다.모든 데이터베이스가 시퀀스를 지원하지 않습니다. MySQL (5.x 이하)에서는 지원되지 않으며, 일부 MariaDB 버전에서만 지원됩니다.
IDENTITY 전략
IDENTITY는 기본 키 생성을 데이터베이스에 위임하는 전략으로 MySQL에서는 AUTO_INCREMENT 기능을 사용합니다.
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id;
IDENTITY 전략의 동작 흐름
- em.persist(user) 호출
- JPA는 즉시 INSERT SQL을 실행
- 데이터베이스가 AUTO_INCREMENT를 통해 id 값을 생성 및 반환
- 반환된 id 값이 user 엔티티에 할당
- 1차 캐시에 저장
IDENTITY 전략의 한계
시퀀스 전략과는 달리 쓰기 지연이 불가능 해지며 persist() 호출 시마다 INSERT SQL이 실행되어, 배치 작업에 최적화하기 어렵습니다. 그렇게 되다 보니 hibernate.jdbc.batch_size를 설정해도 IDENTITY 전략은 배치가 작동하지 않습니다.
데이터베이스별 키 전략 지원 여부DBMSSEQUENCE 지원 여부IDENTITY 지원 여부
| DBMS | SEQUENCE 지원 여부 | IDENTITY 지원 여부 |
| MySQL | ❌ (5.x 이하) | ✅ (AUTO_INCREMENT) |
| MariaDB | ✅ (10.3 이후) | ✅ (AUTO_INCREMENT) |
| PostgreSQL | ✅ | ✅ |
| Oracle | ✅ | ❌ |
| SQL Server | ✅ | ✅ |
| H2 | ✅ | ✅ |
MySQL 8.0부터는 SEQUENCE가 지원되지만 여전히 IDENTITY가 일반적입니다. MariaDB는 최근 버전에서 SEQUENCE를 지원합니다.
SEQUENCE가 주로 사용되는 분야:
| 대규모 데이터 처리 시스템 |
| 글로벌 서비스 및 다중 DB 환경 |
| 트랜잭션 성능이 중요한 서비스 |
TABLE 전략
TABLE 전략은 키 생성을 위한 전용 테이블을 만들어 기본 키를 관리합니다. 데이터베이스에 SEQUENCE 객체가 없을 때, 또는 데이터베이스 독립성을 유지해야 할 때 사용됩니다.
@TableGenerator(
name = "MEMBER_TABLE_GEN",
table = "KEY_GEN_TABLE",
pkColumnValue = "MEMBER_SEQ",
allocationSize = 1
)
@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = "MEMBER_TABLE_GEN")
private Long id;
TABLE 전략의 동작 방식
- KEY_GEN_TABLE이라는 별도의 테이블이 생성됩니다.
- 이 테이블은 키 값을 저장하며, next_val 컬럼을 통해 키 값을 관리합니다.
- persist() 호출 시 JPA는 KEY_GEN_TABLE 테이블에 접근하여 다음 키 값을 조회합니다.
- 조회된 키 값을 엔티티에 할당한 후, 영속성 컨텍스트의 1차 캐시에 등록합니다.
- 트랜잭션 커밋 시 INSERT SQL이 실행됩니다.
테이블 구조 예시
CREATE TABLE KEY_GEN_TABLE (
sequence_name VARCHAR(50) PRIMARY KEY,
next_val BIGINT
);
TABLE 전략의 장점
모든 데이터베이스에서 사용할 수 있으며, 데이터베이스 독립성이 보장됩니다.
TABLE 전략의 단점
키를 조회하기 위해 항상 테이블에 접근해야 하기에 성능 저하 이슈가 있을 수 있고. 다중 트랜잭션이 KEY_GEN_TABLE에 접근할 경우 충돌 가능성이 있기에 추가적인 테이블이 필요합니다.
영속성 컨텍스트와 키 매핑
영속성 컨텍스트는 JPA가 엔티티 객체를 관리하는 메모리 공간입니다. persist()를 호출하면 엔티티는 영속성 컨텍스트에 저장이 되며 영속성 컨텍스트에는 1차 캐시가 존재하며, 이를 통해 엔티티를 관리하기에 1차 캐시에 저장되기 위해서는 반드시 식별자(PK)가 필요합니다.
IDENTITY 전략
- persist() 호출 → 즉시 INSERT SQL 실행
- 데이터베이스가 AUTO_INCREMENT를 통해 생성된 식별자 값을 반환
- 반환된 식별자를 엔티티에 할당
- 영속성 컨텍스트의 1차 캐시에 등록
IDENTITY 전략은 키 값을 얻기 위해 즉시 DB와 통신해야 하므로 쓰기 지연 전략이 불가능합니다.
SEQUENCE, TABLE 전략
- persist() 호출 → JPA는 데이터베이스로부터 키 값을 미리 조회
- 조회된 키를 엔티티에 할당
- 영속성 컨텍스트의 1차 캐시에 등록
- 실제 INSERT SQL은 트랜잭션 커밋 시점에 실행
SEQUENCE 및 TABLE 전략은 쓰기 지연 전략을 지원하며, 여러 persist() 호출이 한 번의 트랜잭션에서 일괄 처리됩니다.
각 전략의 비교
전략특징 INSERT 실행 시점쓰기 지연 전략배치 최적화
| 전략 | 특징 | INSERT 실행 시점 | 쓰기 지연 전략 | 배치 최적화 |
| IDENTITY | DB가 키를 자동 생성 | persist() 즉시 | ❌ 불가능 | ❌ 비효율적 |
| SEQUENCE | 시퀀스를 통해 키를 미리 확보 | 트랜잭션 커밋 시 | ✅ 가능 | ✅ 효율적 |
| TABLE | 키 생성 전용 테이블 사용 | 트랜잭션 커밋 시 | ✅ 가능 | ❌ 성능 저하 |
| AUTO | 데이터베이스 방언에 따라 전략 선택 | DB 방언에 따라 다름 | DB 방언에 따라 다름 | 상황에 따라 다름 |
'spring' 카테고리의 다른 글
| 스프링 3대 기술 (0) | 2025.09.18 |
|---|---|
| [DB] 낙관적 락 vs 비관적 락 (2) | 2024.11.30 |
| 스프링에서 쓰레드는 어떻게 사용되고 멀티쓰레드는 언제 사용할까? (1) | 2024.11.20 |
| JPA에서의 N+1 문제란? (0) | 2024.09.24 |
| AOP와 스프링 AOP란? (0) | 2024.09.23 |