JPA에서 ID는 언제 만들어지고, 언제 DB에 저장될까?

2025. 10. 24. 13:18·Backend Programming

JPA를 사용하다 보면 이런 의문이 생깁니다.

“save() 직후 ID가 생기는데, DB에 저장 된건가?”

 

이 질문의 답은 트랜잭션의 동작 흐름 안에 있습니다.

persist(), flush(), commit()은 각각 “메모리에 저장 -> SQL 실행 -> 트랜잭션 확정” 단계를 의미하며, ID는 이 과정 속에서 점진적으로 생성되고 확정됩니다.

 

이 글에서는 트랜잭션 내부에서 ID가 생성되고, DB에 반영되고, 다른 트랜잭션에서 보이게 되는 전 과정을 순서대로 살펴보겠습니다.

 

1.  비영속 상태

ScheduleEntity schedule = new ScheduleEntity();
System.out.println(schedule.getId()); // 대부분 null (직접 세팅 안 했다면)

단순히 new 한 상태는 JPA가 아직 관여하지 않은 비영속(Transient) 상태입니다.

즉, Hibernate가 관리하지 않기 때문에 ID가 세팅되지 않습니다.

 

UUID나 @GeneratedValue(strategy = GenerationType.UUID)라면 생성자에서 바로 값이 들어올 수 있지만, 일반적으로 AUTO_INCREMENT, IDENTITY, SEQUENCE 전략이라면 이 시점에는 ID = null 입니다.

2. save 호출 시점 (영속 상태)

scheduleRepository.save(schedule);

 

이때 비로소 Hibernate가 엔티티를 영속성 컨텍스트에 등록하고,

@GeneratedValue(strategy = …) 전략에 따라 ID를 생성하거나 조회합니다.

전략 ID 생성 타이밍 설명
IDENTITY INSERT SQL 실행 시 Hibernate가 즉시 INSERT를 날리고 DB의 AUTO_INCREMENT 결과를 getGeneratedKeys()로 받아옴
SEQUENCE save() 직후 DB에서 nextval을 미리 조회하여 ID를 세팅 (INSERT는 flush 때 실행)
TABLE save() 직후 ID 테이블을 조회해 새 번호를 가져와 세팅 (INSERT는 flush 때 실행)
UUID new 시점 또는 엔티티 생성자 내부 save 전에도 이미 존재

 

3. save() 이후의 상태

System.out.println(schedule.getId()); // 이제는 값이 있음

 

save() 시점에 이미 Hibernate가 ID를 생성하거나 조회하므로 이제부터 ID는 항상 존재합니다.

다만, 아직 flush() 전이라 SQL이 DB에 반영되었을 수도 있고 아닐 수도 있습니다.

(IDENTITY면 즉시 반영, SEQUENCE면 flush 때 반영)

이렇게 id는 생성되는 방식을 알았는데 해당 id를 어느 영역까지 사용할 수 있을까?

@Service
@RequiredArgsConstructor
public class IdLifecycleExampleService {

    private final EntityManager em;

    @Transactional
    public void idLifecycleExample() {

        // 1️⃣ new — 비영속 상태
        ScheduleRepeatEntity repeat = new ScheduleRepeatEntity();
        repeat.setTitle("before save");
        System.out.println("new 이후 → id = " + repeat.getId()); // ❌ null

        // 2️⃣ persist/save — 영속성 컨텍스트 등록
        em.persist(repeat);
        System.out.println("persist 이후 → id = " + repeat.getId()); // ✅ 존재 (IDENTITY면 즉시, SEQUENCE면 미리 할당)
        // 하지만 아직 flush 전이므로 DB에는 반영되지 않았을 수도 있음

        // 3️⃣ flush — SQL 실제 전송(DB에 반영)
        em.flush(); // 이 시점에 INSERT SQL 발생
        System.out.println("flush 이후 → id = " + repeat.getId()); // ✅ 동일한 id (변화 없음)

        // DB 직접 확인
        Long count = em.createQuery("SELECT COUNT(r) FROM ScheduleRepeatEntity r", Long.class).getSingleResult();
        System.out.println("flush 이후 DB 조회 count = " + count); // ✅ 1 (DB에 반영됨)

        // 4️⃣ commit — 트랜잭션 종료 후
        // commit은 @Transactional이 끝날 때 자동으로 발생하므로,
        // 여기서 별도 출력은 로그 상에서 확인 가능
    }
}

 

시점에 따른 id의 존재 여부

시점 상태 ID 존재 여부 DB 반영 여부 JDBC 접근 가능 여부/ FK 검증
new 비영속 상태 ❌ 없음 ❌ ❌
persist/save 영속 상태 (1차 캐시) ✅ 생성됨 ❌ (flush 전) ❌
flush DB 반영됨 (트랜잭션 미커밋) ✅ 그대로 유지 ✅ INSERT 반영 ✅ 가능
commit DB 확정 (영구 적용) ✅ 유지 ✅ 영구 반영 ✅ 가능 (다른 트랜잭션에서도 조회 가능)

 

JPA -> DB 전체 데이터 저장 경로

단계 논리적 영역 물리적 저장 위치 주요 역할
persist() 이후 영속성 컨텍스트
(1차 캐시 포함)
Spring JVM 힙 메모리 (RAM) 엔티티 객체를 HashMap(EntityKey → Entity) 형태로 관리
flush() 이후 DB 버퍼 풀
(InnoDB Buffer Pool)
DB 서버의 메인 메모리 (RAM) SQL 실행 결과가 메모리 버퍼에 반영 (아직 디스크 기록 X)
commit() 시점 Redo / Undo Log
(트랜잭션 로그 영역)
DB 서버 디스크 (스토리지의 로그 파일 영역) 트랜잭션 커밋 시 Redo Log를 디스크로 flush(fsync)하여 복구 가능 상태로 만듦
Checkpoint / Lazy Write 데이터 파일
(물리적 테이블 저장소)
DB 서버 디스크 (HDD / SSD의 .ibd / .frm 파일) Buffer Pool의 Dirty Page가 디스크 파일로 기록됨
이후 (다른 트랜잭션 접근 가능) 커밋된 데이터 가시화 DB 디스크 + OS 캐시 메모리 모든 트랜잭션에서 읽을 수 있는 상태

 

persist와 save의 차이

상황 persist save
이미 DB에 존재하는 엔티티에 호출 시 ❌ 예외(EntityExistsException) 발생 가능 ✅ merge() 동작으로 UPDATE

 

마무리

JPA에서 ID는 단순히 “DB에 INSERT하면 생기는 값”이 아닙니다.

Hibernate는 @GeneratedValue 전략과 영속성 컨텍스트를 활용해, DB와 JVM 사이에서 식별자 값을 미리 관리하고 동기화합니다.

저작자표시 (새창열림)

'Backend Programming' 카테고리의 다른 글

정말 HTTPS에 대해서 알고 있는가?  (1) 2025.10.28
데이터베이스 구조 리팩토링 및 마이그레이션 경험 공유  (3) 2025.07.30
빌드 실패 디버깅  (1) 2025.03.07
CI/CD? 배포 자동화를 해보자  (0) 2024.12.13
EC2를 활용한 HTTPS 및 도메인 설정  (3) 2024.12.12
'Backend Programming' 카테고리의 다른 글
  • 정말 HTTPS에 대해서 알고 있는가?
  • 데이터베이스 구조 리팩토링 및 마이그레이션 경험 공유
  • 빌드 실패 디버깅
  • CI/CD? 배포 자동화를 해보자
chanheess
chanheess
'왜' 그렇게 했는가?에 대한 생각으로 공부 및 작업의 저장관리
  • chanheess
    왜 그렇게 생각했는가?
    chanheess
  • 전체
    오늘
    어제
    • 분류 전체보기
      • Backend Programming
      • Game Programming
        • Unreal
        • DirectX
      • C++
        • Memo
        • Basic
        • Effective Modern
      • Algorithm
        • Memo
        • Baekjoon
        • Programmers
        • HackerRank, LeetCode
      • Data Structure
      • Design Pattern
      • Etc
        • Memo
        • Daily Log
        • Book
  • 최근 글

  • 최근 댓글

  • 태그

    위클리 챌린지
    알고리즘
    티스토리챌린지
    JWT
    JPA
    프로그래머스
    c++ 기초 플러스
    spring
    SpringSecurity
    Java
    백준
    오블완
    dp
    dfs
  • hELLO· Designed By정상우.v4.10.0
chanheess
JPA에서 ID는 언제 만들어지고, 언제 DB에 저장될까?
상단으로

티스토리툴바