본문 바로가기
JPA

IDENTITY 식별자 생성 전략과 persist()의 관계

by sangyunpark99 2025. 2. 3.
"IDENTITY전략을 사용하면 persist()시 왜 
즉시 INSERT 쿼리문이 나갈까?"

 

이번글은 식별자 생성 전략인 IDENTITY와 영속성 컨텍스트에 엔티티를 영속화하는데 사용되는 persist()메서드와의 관계에 대해 알아보겠습니다.

 

IDENTITY 식별자 생성 전략이란 무엇일까요?

 

IDENTITY 식별자 생성 전략

JPA에서 엔티티의 기본키를 자동으로 생성하는 방식 중 하나입니다.

엔티티 생성시 기본키를 직접 할당하지 않아도, 데이터베이스에서 자동으로 생성할 수 있도록 책임을 위임하는 방식입니다.

또한, IDENTITY전략은 MySql사용시 자주 선택되는 전략입니다.

IDENTITY 식별자를 사용하면 DB에선 어떠한 일이 발생될까요?

 

IDENTITY 전략을 사용하면 데이터베이스가 자동으로 기본 키 값을 생성하게 됩니다.

특히 MySQL에서는 AUTO_INCREMENT 기능을 활용하여 ID가 자동으로 증가합니다.

쉽게 말해, DB에 데이터를 INSERT할 때, AUTO_INCREMENT 기능을 이용해 자동으로 증가된 ID 값을 설정합니다. 일반적으로 이전에 저장된 가장 큰 ID 값보다 1이 증가한 값이 할당됩니다.

 

JPA에서는 IDENTITY 전략을 어떻게 사용할까요? 

 

코드 예제


UserEntity.class

package com.example.spring_study_test.entity;

import jakarta.persistence.*;

@Entity
public class UserEntity {

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

    protected UserEntity() {

    }

    public UserEntity(String name) {
        this.name = name;
    }
    
    public Long getId() {
	 return this.id;
  }
}

엔티티를 생성할 때 id값을 직접 설정하지 않고, name 필드 값만 입력합니다.

이는 ID 생성이 JPA가 아닌 데이터베이스에서 자동으로 이루어지기 때문입니다.

 

 

IDENTITY 전략을 사용하기위해 명시해주어야 하는 코드는 다음과 같습니다.

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

 

IDENTITY 전략을 사용하면 정말 데이터베이스에서 자동으로 이루어질까요?

 

IDENTITY 전략 테스트

테스트는 간단하게 2개의 UserEntity를 생성한 후, persist()메서드를 사용해서 데이터베이스에 insert하겠습니다.

테스트 코드는 다음과 같습니다.

package com.example.spring_study_test;

import com.example.spring_study_test.entity.UserEntity;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.transaction.Transactional;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.Commit;

@SpringBootTest
@Transactional
@Commit
public class InsertUserTest {

    @PersistenceContext
    private EntityManager em;

    @Test
    void givenTwoUsers_whenPersist_thenIdsAreAutoGenerated() throws Exception{
        //given
        UserEntity user1 = new UserEntity("user1");
        UserEntity user2 = new UserEntity("user2");

        //when
        em.persist(user1);
        em.persist(user2);

        Long userId1 = user1.getId();
        Long userId2 = user2.getId();

        //then
        UserEntity findUser1 = em.find(UserEntity.class, userId1);
        UserEntity findUser2 = em.find(UserEntity.class, userId2);

        Assertions.assertNotNull(findUser1);
        Assertions.assertNotNull(findUser2);
    }
}

 

아이디 값을 넣어주지 않은 2개의 엔티티를 생성하고, persist()메서드를 통해 DB에 두 엔티티를 insert해줍니다.

그후, find()메서드를 사용해서 2개의 엔티티를 조회하고, 조회한 엔티티에 ID값이 존재하는지 assertEquals()메서드로 비교해줍니다.

 

테스트 실행 결과 & DB 확인

테스트 성공했습니다. 다음으로 DB를 확인해보겠습니다.

DB 결과

DB에도 데이터가 잘 들어간 것을 확인할 수 있습니다.

 

혹시 이상한 점을 눈치채지 못했나요? persist()만 해줬는데 왜 INSERT 쿼리가 나갈까요?

 

결론부터 말하면, em.persist()를 호출했을 때 즉시 INSERT 쿼리가 실행되는 것은 기존의 JPA 동작 방식과 다릅니다.
일반적으로 JPA는 영속성 컨텍스트에 쿼리를 임시 저장한 후, flush() 또는 commit()이 호출될 때 한꺼번에 DB에 반영합니다.
하지만 IDENTITY 전략을 사용할 경우, persist() 호출 시점에 즉시 INSERT가 실행된다는 점이 기존 JPA의 동작 방식과 다릅니다.

 

INSERT가 실행된다는 점도 테스트 실행 결과에 나와있는 쿼리문을 통해서도 확인할 수 있습니다.

분명, persists()만 해주었는데도 불구하고, insert 쿼리가 보입니다.

 

IDENTITY 전략은 JPA의 일반적인 방식과 다르게 동작할까요?

 

IDENTITY와 persist()의 관계

IDENTITY 전략을 사용하면, ID 생성이 데이터베이스에서 이루어지기 때문에 JPA는 persist() 호출 시 즉시 INSERT 쿼리를 실행해야 합니다. 만약 즉시 INSERT를 실행하지 않는다면, JPA는 엔티티의 ID 값을 알 수 없기 때문에 영속성 컨텍스트에서 정상적으로 관리할 수 없습니다.

 

ID랑 영속성 컨텍스트랑 무슨 상관이 있나요?

 

JPA의 영속성 컨텍스트는 엔티티를 관리할 때 ID 값을 기준으로 엔티티를 식별합니다.
만약 즉시 INSERT를 실행하지 않는다면, JPA는 ID 값을 알 수 없고, 영속성 컨텍스트에 정상적으로 저장할 수 없습니다.

 

다른 식별자 전략은 어떠할까요?

 

다른 전략으로는 SEQUENCE, TABLE 전략이 존재합니다.

표로 정리하면 다음과 같습니다.

전략 ID생성 주체 persist() 호출 시
INSERT 실행 여부
ID 미리 할당
가능 여부
IDENTITY DB에서 생성 (AUTO_INCREMENT, SERIAL 등) 즉시 INSERT 실행됨
SEQUENCE DB 시퀀스 (PostgreSQL, Oracle 등) 미리 시퀀스 값 가져온 후, 엔티티 캐시에 저장
TABLE JPA가 테이블을 사용하여 관리 ID를 미리 조회 후, 엔티티 캐시에 저장

 

 

정리

IDENTITY 전략은 JPA에서 엔티티의 기본 키를 자동으로 생성하는 방식 중 하나입니다.
엔티티를 생성할 때 기본 키를 직접 할당하지 않아도, 데이터베이스에서 자동으로 생성할 수 있도록 책임을 위임하는 방식입니다.

 

persist() 메서드 호출 시, 즉시 INSERT 쿼리를 실행하여 기본 키 값을 데이터베이스에서 가져옵니다.

따라서, 트랜잭션이 commit()될 때까지 기다리지 않고, 즉시 INSERT가 발생합니다.

MySQL에서는 AUTO_INCREMENT, PostgreSQL에서는 SERIAL과 같은 기능을 활용합니다.