[프로그래밍] JPA

[JPA] JPA의 기본 키 생성 전략

JHVan 2024. 5. 4. 23:32

기본키 적용을 위한 어노테이션:

@Id: 단순히 하나의 필드를 기본키로 지정할 때 사용됨.

 

@IdClass: 복합키를 지원하며, 별도의 클래스를 이용하여 복합키를 정의할 때 사용됨.

@EmbeddedId: 복합키를 임베디드 타입으로 사용할 때 적용되며, 복합키를 내장된 객체로 처리함.

기본키를 어디서 생성할지 결정해야함.

애플리케이션에서 생성하는 방식과 데이터베이스에서 생성하는 방식, 두 가지 기본 키 생성 매커니즘을 결정하는 것이 필요함.

  1. 애플리케이션에서 생성:
    • 자바 프로그램 내에서 유니크한 값을 생성하여 기본 키로 사용함.
    • UUID와 같은 메소드를 사용하여 독립적으로 유니크한 값을 생성함.
    • 데이터베이스 시스템에 독립적이며 다양한 데이터베이스와 호환됨.
  2. 데이터베이스에서 생성:
    • 데이터베이스의 내장 기능을 사용하여 자동으로 유니크한 키를 생성함.
    • 시퀀스(Sequence)와 자동 증가(Auto Increment) 방식이 있음.
      • 시퀀스: 데이터베이스 내에서 사전 정의된 순서로 값을 생성하는 객체를 사용함. Oracle과 PostgreSQL에서 사용됨.
      • 시퀀스(sequence)는 데이터베이스에서 순차적으로 증가하는 숫자를 생성하기 위해 사용되는 객체.
        이는 주로 기본키(primary key)의 값을 자동으로 생성할 때 사용됨. 
        시퀀스는 사용자가 지정한 규칙에 따라 고유한 값을 순차적으로 생성할 수 있으며,
        이 값은 테이블 간에 공유될 수 있음.
        
        시퀀스의 주요 특징:
        시작 값(START WITH): 시퀀스가 생성할 첫 번째 값을 지정한다.
        증가 값(INCREMENT BY): 시퀀스가 각 순번에 적용할 증가량을 지정한다.
        최소값(MINVALUE)과 최대값(MAXVALUE): 시퀀스가 생성할 수 있는 값의 범위를 지정한다.
        사이클 여부(CYCLE): 시퀀스가 최대값에 도달했을 때 최소값으로 다시 시작할지 여부를 지정한다.
        캐시 여부(CACHE): 성능 최적화를 위해 미리 일정량의 시퀀스 값을 메모리에 캐시할지 여부를 지정한다.
        
        시퀀스를 사용하는 이유:
        고유성 보장: 시퀀스는 테이블의 여러 행에 대해 고유한 값을 생성하여 기본키로 사용할 수 있게 한다.
        성능 최적화: 시퀀스 값은 미리 생성되어 캐시될 수 있으므로,
        데이터베이스에 새 행을 삽입할 때마다 새로운 고유값을 생성하는 데 드는 시간을 줄일 수 있다.
        유연성: 사용자가 시퀀스의 시작값, 증가량, 최대값 등을 자유롭게 지정할 수 있어,
        필요에 맞게 시퀀스를 구성할 수 있다.
        시퀀스는 Oracle, PostgreSQL, DB2 등 여러 데이터베이스 관리 시스템(DBMS)에서 지원한다.
        MySQL과 같은 일부 DBMS에서는 내장된 시퀀스 기능 대신 AUTO_INCREMENT 속성을 사용하여
        유사한 기능을 제공한다.
      • Auto Increment: 새로운 레코드마다 숫자를 자동으로 증가시킴. MySQL과 SQL Server에서 사용됨.
    • 데이터베이스가 직접 키를 관리하여 애플리케이션 코드를 간결하게 하며, 키 생성의 일관성과 안정성을 보장함.

기본키 값을 직접 할당하는 경우 @Id 어노테이션을 사용함.

기본키 값을 자동으로 생성하고 싶다면 @GeneratedValue 어노테이션을 적용함.

@GeneratedValue를 사용하여 기본키 값의 자동 생성 방법에는 여러 옵션을 통해 생성 전략을 적용할 수 있음.

 
 

Identity 전략

데이터베이스가 기본키의 생성을 자동으로 관리하는 전략.

새로운 엔티티가 데이터베이스에 저장될 때, 데이터베이스가 자동으로 기본키 값을 생성하고 할당.

MySQL, DB2, Oracle 등의 데이터베이스에서 지원함.

Identy 전략

 

주요 특징은 데이터를 저장할 때, 즉 persist() 메소드를 호출할 때 바로 Insert 쿼리가 실행되며, 이 시점에 데이터베이스에서 새로운 기본키 값이 생성되고 할당.

따라서 엔티티의 기본키 필드에는 저장 직후 바로 실제 데이터베이스에서 생성된 기본키 값을 확인할 수 있음.

 

장점은 구현이 간단하고, 데이터베이스가 기본키 생성을 자동으로 처리하기 때문에 개발자가 기본키 생성 로직을 신경 쓸 필요가 없다.

단점은 persist() 메소드 호출 시마다 즉시 Insert 쿼리가 실행되기 때문에, 성능상의 이슈가 발생할 수 있으며, 일부 JPA 구현체에서는 이러한 동작 방식으로 인해 벌크 삽입(bulk insert) 같은 최적화 작업이 어려울 수 있음.

 

Sequence 전략

데이터베이스의 Sequence 오브젝트를 이용해 기본키를 생성하는 방식.

Oracle, PostgreSQL, DB2와 같이 Sequence 오브젝트를 지원하는 데이터베이스에서 사용할 수 있음.

이 전략을 사용하기 위해서는 @SequenceGenerator 어노테이션을 클래스나 필드에 적용해야 함.

@SequenceGenerator 어노테이션을 통해 Sequence 이름, 초기값, 증가치 등을 설정할 수 있으며, 이러한 옵션을 조정해 기본키 생성 방식을 더 세밀하게 제어할 수 있음.

Sequence 전략

@SequenceGenerator 어노테이션은 customer_generator라는 이름의 시퀀스 생성기를 정의 (name).

이 생성기는 customer_seq라는 이름의 데이터베이스 시퀀스 오브젝트와 연결됨 (sequenceName).

initialValue가 1로 설정되어 시퀀스 값이 1부터 시작하고,

allocationSize가 1로 설정되어 시퀀스 값이 한 번에 1씩 증가하게 됨.

initialValue와 allocationSize는 @SequenceGenerator 어노테이션에서 사용되는 속성들이다.

initialValue: 시퀀스의 시작 값을 지정한다.
예를 들어, initialValue = 1이라고 설정하면 시퀀스가 1부터 시작한다. 
이 값은 시퀀스 오브젝트가 생성될 때 최초로 사용될 값이다.

allocationSize: 시퀀스의 증가량을 지정한다.
allocationSize = 1로 설정하면 시퀀스 값이 1씩 증가한다. 
이 속성은 JPA가 한 번에 메모리에 할당할 시퀀스 값의 수를 결정한다. 
예를 들어,allocationSize가 1이라면 엔티티를 저장할 때마다 새로운 시퀀스 값을 얻기 위해
데이터베이스에 접근해야 한다.
만약 50개의 엔티티를 저장한다면, 
이는 50번의 데이터베이스 시퀀스 접근을 의미한다.
allocationSize = 50이라면 JPA는 시퀀스 값을 50씩 증가시키며, 
JPA는 한 번의 데이터베이스 시퀀스 접근으로 50개의 시퀀스 값을 메모리에 할당하고, 
이후 엔티티를 저장할 때마다 데이터베이스에 별도의 시퀀스 값 요청을 하지 않고 
메모리에서 할당된 값을 사용한다. 
이로 인해 데이터베이스와의 통신 횟수가 줄어들어 성능이 향상되는 효과가 있다.

allocationSize를 크게 설정하면 사용되지 않는 시퀀스 번호가 발생할 수 있다.

allocationSize가 50으로 설정된 경우 
어플리케이션이 시작할 때 시퀀스 값이 1이고, 
첫 번째 엔티티를 데이터베이스에 저장할 때, 
JPA는 1부터 50까지의 시퀀스 값을 할당받는다. 
이때 첫 번째 엔티티에는 시퀀스 값 1이 할당되고,
다음 엔티티가 저장될 때는 2가 할당될 것이다. 
어플리케이션이 10개의 엔티티만 저장하고 종료되면,
11부터 50까지의 시퀀스 값은 사용되지 않게 된다.

다음에 어플리케이션이 재시작되고 새로운 엔티티가 저장될 때,
JPA는 시퀀스 값을 다시 할당받게 되는데,
이때는 51부터 시작하여 다시 50개의 값을 할당받는다. 
따라서, 11부터 50까지의 시퀀스 값은 어떤 엔티티에도 사용되지 않는 채로 남게 되어,
이는 시퀀스 값의 불연속성을 초래한다.
자주 재시작되는 어플리케이션에서 더욱 두드러질 수 있으며, 
시퀀스 값의 연속성이 중요한 경우에는 allocationSize를 신중하게 고려해야 한다.

 

@Id 어노테이션은 해당 필드가 테이블의 기본 키임을 나타냄.

@GeneratedValue 어노테이션은 기본 키의 값을 자동으로 생성하기 위한 전략을 지정하는데 사용됨

strategy 속성을 GenerationType.SEQUENCE로 설정하여 customer_generator라는 이름의 시퀀스 생성기를 사용.

Customer 엔티티의 인스턴스가 데이터베이스에 Insert될 때 customer_seq 시퀀스에서 다음 값이 자동으로 id 필드에 할당되어 각 인스턴스마다 고유한 기본 키 값이 부여됨.

 

만약 DB 에 sequence 가 이미 만들어져 있다면, Id 필드 위에 @SequenceGenerator(name =~ , sequenceName=~) 로.

 

Table 전략

Table 기본키 생성 전략은 특정한 테이블을 사용하여 엔티티의 기본키를 생성하는 방식.

Table 기본키 생성 전략은 별도의 테이블을 생성하기 때문에 데이터베이스 종류에 영향을 받지 않음.

Table 생성 전략을 적용하기 위해서는 @TableGenerator 어노테이션이 필요하며 여러 옵션을 적용할 수 있음.

Table 생성 전략은 테이블 생성과 키값 증가를 위한 update가 실행되기 때문에 성능에 대한 고려가 필요.

Table 전략

@TableGenerator 어노테이션을 사용하여 기본키 생성을 위한 별도의 테이블(customer_id)을 지정.

이 테이블에서는 id_name 컬럼에 customer_id라는 값을 가지며, 실제로 기본키 값이 저장되는 컬럼은 next_value로 지정.

initialValue 0: 기본키 값은 0부터 시작, allocationSize 1: 기본키 값은 하나씩 증가.

@TableGenerator 어노테이션을 사용하여 Table 생성 전략을 적용할 때의 옵션:
name: 생성기의 이름을 지정
이 이름은 @GeneratedValue 어노테이션의 generator 속성과 함께 사용된다.
table: 기본키 값을 저장할 테이블의 이름을 지정
pkColumnName: 테이블에서 기본키 엔티티의 이름을 저장하는 열의 이름을 지정
valueColumnName: 테이블에서 기본키의 현재 값을 저장하는 열의 이름을 지정
pkColumnValue: 기본키 값을 저장하는 테이블에서 사용될 특정 엔티티의 이름을 지정
initialValue: 기본키의 초기 값 설정. (기본값은 0)
allocationSize: 기본키 값의 증가 크기를 설정 (기본값은 50)

@GeneratedValue 어노테이션의 strategy 속성에 GenerationType.TABLE을 지정하고, generator 속성으로 id_generator를 지정하여 Customer 엔티티의 id 필드가 이 테이블 생성 전략을 사용하여 생성.

주의사항

Table 기본키 생성 전략은 매번 엔티티를 저장할 때마다 키 생성을 위한 테이블을 조회하고, 해당 테이블의 값을 update하여 새로운 키 값을 생성하므로

  • 데이터베이스 액세스 증가: 키를 생성할 때마다 테이블에 접근하여 조회 및 업데이트를 실행하여 추가적인 데이터베이스 Input/Output(I/O) 발생.
  • 병렬 처리 시 충돌 가능성: 동시에 여러 트랜잭션이 같은 테이블을 업데이트하려 할 때 충돌이 발생할 수 있고 해결 위한 락킹 메커니즘이 성능에 영향을 줄 수 있음.

'[프로그래밍] JPA' 카테고리의 다른 글

[JPA] JPA 와 연관관계  (0) 2024.05.05
[JPA] JPA와 Column  (0) 2024.05.05
[JPA] Entity Mapping  (0) 2024.05.04
[JPA] JPA의 영속성 컨텍스트  (0) 2024.05.03
[JPA] JPA 와 DB Dialect  (0) 2024.05.01