[JPA] JPA의 필수개념_2 (식별자 전략 (@Id, @GeneratedValue))

2025. 6. 26. 23:09·공부일기../JPA

1.  `@Id`: 기본키 필드 표시

JPA에서 `@Id`는 엔티티의 기본 키를 지정하는 키워드이다. 

테이블과 엔티티를 매핑 할때 식별자로 사용할 필드 위에 `@Id`어노테이션을 붙여 테이블의 Primary Key와 연결 시켜줘야한다.

 

컬럼 명을 지정하지 않으면 camelCase로 작성된 필드명을 snake_case로 바뀐 테이블 컬럼을 찾아서 매핑시켜준다.

ex) memberId -> member_id , orderItemId -> order_item_id 

 

`@Column` 어노테이션을 활용하여 테이블의 pk 컬럼을 따로 지정할 수도 있다.

@Entity
public class Member {
    @Id  
    @Column(name = "member_id") // 컬럼명 따로 지정
    private Long id;  
}

 

이렇게 `@Id`로 식별자필드와 테이블의 PK를 매핑만 시켜놓으면

식별자로 사용될 값을 일일히 수동으로 넣어줘야 하는 불편함이 있는데, `@GeneratedValue` 를 사용하면 이를 해결할 수 있다.

 

`@GeneratedValue` 어노테이션을 사용하면 식별자 값을 자동 생성 시켜줄 수 있다. 

(그냥 일련번호같은 숫자를 자동으로 증가시켜줄수있다는 뜻이다. MySql의 AUTO_INCREMENT,  Oracle의 시퀀스와 같은 개념이다. 당연함 저 데이터베이스를 활용할때 JPA가 기본키 생성을 하는거라 개념이 같을수밖에없음!)

 

`@GeneratedValue`에는 3가지 전략이 있고, JPA에게 전략 선택을 위임하는 옵션인 AUTO 옵션을 포함해서

총 4가지 옵션이 존재한다.

 


2. 식별자 전략 (@Id, @GeneratedValue)

 

`@GeneratedValue`는 기본 키를 어떻게 자동 생성할지 설정하는 어노테이션이다.

아래 표는 4가지 옵션에 관한 간략한 설명이다.

 

전략 설명 DB 종속성 특징 DB
AUTO JPA가 알아서 결정 (기본값) O DB에 따라 IDENTITY나 SEQUENCE 등 자동 선택
*주의 :하이버네이트를 무조건 믿어선 안된다!
자동선택
IDENTITY DB가 자동 생성
(MySQL의 AUTO_INCREMENT 같은 것)
O insert할 때 ID 없음 → DB가 넣어줌 MySQL에서 가장 흔함
SEQUENCE DB 시퀀스 오브젝트 사용
(Oracle, PostgreSQL 등)
O 시퀀스에서 값을 미리 가져와서 insert PostgreSQL, Oracle에서 사용
TABLE 별도 키 생성용 테이블에서 ID 관리 X DB 독립적이지만 성능 떨어짐 모든 DB 가능!

 

 @GeneratedValue : ID( 기본키 ) 자동 생성 

식별라고 일컫는게 일련번호같은 것을 만들어주는것같다. 순자를 순차적으로 늘리는것인데 

JPA가 값을 자동생성하게 만들겠다는 뜻이다. `strategy = ...`는 어떤방식으로 생성할지 지정해주는것 (위의 4가지 방식중 하나)

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

 


2-1. IDENTITY 키워드 (MySQL에서 사용)

"DB가 자동으로 ID 값을 만들어줘!"

 

사전 프로젝트 게시판 구현할때 MySql을 사용했기때문에 게시판의 번호를 자동증가하기위해 `IDENTITY`를 사용해보았다.

 

  • `INSERT INTO member (name) VALUES ('홍길동')`
  • → DB가 `id` 값을 자동으로 채워줌 (MySQL에서 흔히 쓰는`AUTO_INCREMENT`) 
  • JPA는 이 값을 insert 이후에 DB로부터 받아옴
  • 단점: `em.persist()` 즉시 insert됨 → 배치 INSERT 최적화 어려움
-- DB에 이런 테이블이 있다면
CREATE TABLE member (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255)
);
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

 


 

2-1-1. IDENTITY 동작 흐름 방식

Member member = new Member("홍길동");
em.persist(member);

내부 동작

  1. `em.persist(member)` 호출하면,
  2. JPA는 즉시 INSERT SQL을 실행함
    1. (디비에 진짜 찐찐 들어간다는뜻 영속성이아니라)
    2. 사유 : DB가 ID를 만들어줘야 하기 때문!!!!
    3. 그래서 Hibernate는 INSERT를 바로 실행해야만 member.getId() 값을 알 수 있음 
  3. DB가 ID 값을 생성해줌 (예: 1, 2, 3...)
  4. 그 ID 값이 member.id에 자동으로 채워짐

특징

  • ID가 생성되기 전에는 insert할 수 없음
  • 그래서 persist() = 곧바로 insert 실행됨
  • 배치 INSERT 최적화 불가 
-- 바로 실행됨
INSERT INTO member (username) VALUES ('홍길동');
-- 그리고 DB가 자동으로 id=1 부여

 


📍 배치 최적화란~? 

더보기

배치(Batch) 란?

한 번에 여러 건의 작업을 묶어서 처리하는 것
예를 들어, 회원 100명을 한 명씩 처리하는 대신
→ 10명씩 묶어서 처리하는것이다. 훨~씬 빠름 


배치 INSERT 예시 

for (int i = 0; i < 1000; i++) {
    em.persist(new Member("user" + i));

    if (i % 50 == 0) {
        em.flush();   // DB에 반영
        em.clear();   // 메모리 비우기
    }
}

→ 이렇게 하면 1000명을 한 번에 다 처리하지 않고, 50명씩 나눠서 처리할 수 있다.

배치처리는 회사에서도 정말많이 사용해서 jpa에서도 최적화된 배치처리를 알면 좋을것이라고 생각했다. 


배치 insert를 하려면 ID를 미리 알아야 한다.
즉, insert 전에 ID가 있어야 → 쿼리를 모아서 한 번에 날릴 수 있다.


전략에 따른 차이

전략배치 insert 가능여부 이유
IDENTITY 불가능 DB가 insert 후에 ID를 생성 → 한 건씩 insert해야 함
SEQUENCE + allocationSize ≥ 1 가능 미리 ID 확보 가능 → 쿼리를 모아서 한 번에 insert 가능
 

항목 설명
배치 최적화란? 여러 insert 쿼리를 모아서 한 번에 처리하는 것
왜 중요? 성능 향상, DB round trip 감소
가능한 조건 ID를 미리 확보할 수 있어야 함 (SEQUENCE + allocationSize 필요)
불가능한 경우 IDENTITY 전략 (ID를 DB가 생성하므로 insert 시점에 몰라서 배치 불가)

 

 


2-2. SEQUENCE 키워드 (PostgreSQL, Oracle에서 사용)

"미리 시퀀스에서 ID 번호 받아올게~~"

 

  • JPA가 먼저 `SELECT nextval('member_seq')`로 ID 값을 미리 가져옴
  • 그 다음 `INSERT` 실행
  • ID 값을 insert 전에 미리 안다는 게 큰 차이점
  • 배치 시 insert 최적화

 

완전 걍 오라클문법인듯? 나는 회사에서 오라클을 사용하기때문에 시퀀스를 잘 사용하는데

먼저 값을 가져와서 필요한 곳에 넣어준다

jpa에서도 마찬가지로 db에서 시쿼스를 미리 생성해줘야 사용할 수있다.

 

CREATE SEQUENCE member_seq START WITH 1 INCREMENT BY 1;
@SequenceGenerator(
    name = "member_seq_gen",
    sequenceName = "member_seq", // DB에 생성한 시퀀스 이름
    allocationSize = 50 // 기본값은 50 ( DB 시퀀스를 몇 개씩 미리 할당받을지 정하는 옵션)
)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "member_seq_gen")
private Long id;

 

2-2-1. SEQUENCE 동작 흐름 방식

  • em.persist(member); 이 시점엔 쿼리 아직 안 날아감
  • JPA는 "영속 상태"만 등록하고
  • flush() 또는 트랜잭션 commit 시점까지 대기했다가 INSERT 실행됨
Member member = new Member("홍길동");
em.persist(member);

 내부 동작

  1. em.persist(member) 호출 시,
  2. 먼저 시퀀스에서 ID를 미리 가져옴
SELECT nextval('member_seq');

   3. 그 ID를 엔티티에 할당 (member.id = 100)

   4. 이후에 INSERT 실행

INSERT INTO member (id, username) VALUES (100, '홍길동');

특징

  • ID를 먼저 확보하므로,
  • JPA는 쓰기 지연(쓰기 모아서 처리) 가능 → 배치 insert에 유리
  • 성능 최적화에 더 적합

 


📍 allocationSize란?

더보기

가정

  • allocationSize = 50
  • 현재 DB 시퀀스 값: 1

동작:

  1. JPA가 시퀀스를 한번 조회해서 1~50번 ID 범위를 확보함
  2. 그 다음 insert는 DB 시퀀스를 다시 조회하지 않고,
    메모리에서 2, 3, 4, ..., 50까지 ID를 직접 할당
  3. 50개를 다 쓰고 나면 다시 시퀀스 조회 → nextval = 51 → 51~100 확보

미리 범위 확보하는 이유

🔸 이유: 성능 최적화 => 이래서 배치할때 좋은것임!

  • 매번 DB에 SELECT nextval() 하려면 느리니까
  • 한번에 여러 개 미리 받아와서 메모리에 캐싱하는 방식

주의할 점

항목 설명
ID가 건너뛸 수 있음 서버 재시작 등으로 미리 받은 ID를 안 쓰고 버릴 수도 있음
(예: 1~50 받아놨는데 3번까지만 쓰고 종료되면, 4~50은 날아감)
성능은 확실히 좋아짐 배치 insert 등에서 매우 유리
필요 시 allocationSize=1로 조정 ID 정밀하게 관리하고 싶으면 (대신 성능은 떨어짐)

 

'공부일기.. > JPA' 카테고리의 다른 글

[JPA] Spring Data JPA 페이징 (3/3) - 성능 최적화와 테스트  (0) 2025.12.13
[JPA] Spring Data JPA 페이징(2/3) - 실무 패턴과 동적 쿼리  (0) 2025.12.11
[JPA] Spring Data JPA 페이징 (1/3) - 기본 개념과 핵심 객체  (0) 2025.12.08
[jpa] BaseEntity와 JPA Auditing - 동작 원리 , 중복필드 제거 (예시코드)  (0) 2025.10.18
[JPA] JPA의 필수개념_1 (JPA정의, Projection)  (0) 2025.06.26
'공부일기../JPA' 카테고리의 다른 글
  • [JPA] Spring Data JPA 페이징(2/3) - 실무 패턴과 동적 쿼리
  • [JPA] Spring Data JPA 페이징 (1/3) - 기본 개념과 핵심 객체
  • [jpa] BaseEntity와 JPA Auditing - 동작 원리 , 중복필드 제거 (예시코드)
  • [JPA] JPA의 필수개념_1 (JPA정의, Projection)
s0-0mzzang
s0-0mzzang
공부한것을 기록합니다...
  • s0-0mzzang
    승민이의..개발일기..🐰
    s0-0mzzang
  • 전체
    오늘
    어제
    • 전체~ (108)
      • 마음가짐..! (10)
      • 공부일기.. (76)
        • weekly-log (6)
        • Spring (19)
        • Java (18)
        • DataBase (10)
        • git (2)
        • JPA (6)
        • kafka (1)
        • Backend Architecture (3)
        • Troubleshooting (삽질..ㅋ) (2)
        • Cloud (1)
        • Docker (2)
        • 알고리즘 (1)
        • 리액트 (2)
        • Infra (3)
      • 하루일기.. (22)
        • 그림일기 (8)
        • 생각일기 (14)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • 깃허브
  • 공지사항

  • 인기 글

  • 태그

    ADC 환경
    spring
    ERD
    spring boot
    TDD
    Paging
    다짐
    리팩토링
    JPA
    React
    BufferedReader
    인프라 기초
    항해99
    항해플러스
    스프링부트
    swagger
    자바
    SpringBoot
    StringTokenizer
    MySQL
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
s0-0mzzang
[JPA] JPA의 필수개념_2 (식별자 전략 (@Id, @GeneratedValue))
상단으로

티스토리툴바