[자바 ORM 표준 JPA] JPA 기본키 매핑

[자바 ORM 표준 JPA] JPA 기본키 매핑

기본키 매핑


기본 키 매핑 어노테이션#


  • @Id
  • @GeneratedValue
@Id @GeneratedValue(strategy = GenerationTpye.AUTO)
private Long id;

기본 키 매핑 방법#


  • 직접 할당 : @Id 만 사용
  • 자동 생성(@GeneratedValue)
    • IDENTITY : 데이터베이스에 위임, MySLQ)
    • SEQUENCE : 데이터베이스 시퀀스 오브젝트 사용, ORACLE
      • @SequenceGenerator 필요
  • TABLE: 키 생성용 테이블 사용, 모든 DB에서 사용
    • @TableGenerator 필요
  • AUTO: 방언에 따라 자동 지정, 기본값

Id 직접할당 - @Id 사용#


Member.java 기본 키 매핑에 좀더 집중하기 위해 Memeber의 Id를 String 으로 변경하고, Id, name을 제외한 나머지를 일단 제거합니다.

   package hellojpa;

import javax.persistence.*;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;

@Entity
public class Member {

    @Id
    private String id;

    @Column(name="name", length = 10) 
    private String userName;


    public Member() {
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }
}

JpaMain.java

			Member member1 = new Member();
            member1.setId("USER_A"); // 아이디 채번을 직접하여 할당
            member1.setUserName("유저A");
            em.persist(member1);

            Member member2 = new Member();
            member2.setId("USER_B");
            member2.setUserName("유저B");
            em.persist(member2);

            tx.commit();

contact

contact

Id 자동할당 - @GeneratedValue#


GeneratedValue의 전략은 AUTO, IDENTITY, SEQUENCE, TABLE가 있으며,
AUTO는 방언에 따라 다르게 생성

    @GeneratedValue(strategy = GenerationType.AUTO) 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 위임함
    @eneratedValue(strategy = GenerationType.SEQUENCE) 
    @GeneratedValue(strategy = GenerationType.TABLE) 
    

GenerationType.IDENTITY#


GenerationType.IDENTITY - 특징#

  • 기본 키 생성을 데이터베이스에 위임
  • 주로 MySQL, PostgreSQL, SQL Server. DB2에서 사용
    예) MySQL의 AUTO_INCREMENT
  • JPA는 보통 트랜잭션 커밋 시점에 INSERT SQL 실행
  • AUTO_INCREMENMT는 데이터베이스에 INSERT SQL을 실헹한 이후에 ID 값을 알 수 있음
  • IDENTITY 전략은 em.persist() 시점에 즉시 INSERT_SQL 실행하고 DB에서 식별자를 조회
    @Id
    @GeneratedValue(strategy  = GenerationType.IDENTITY) 
    private String id;
    
Hibernate: 
    
    drop table Member if exists
Hibernate: 
    
    create table Member (
       id varchar(255) generated by default as identity,
        name varchar(10),
        primary key (id)
    )
12월 26, 2021 10:48:37 오후 org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl getIsolatedConnection
INFO: HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@2a2da905] for (non-JTA) DDL execution was not in auto-commit mode; the Connection 'local transaction' will be committed and the Connection will be set into auto-commit mode.
12월 26, 2021 10:48:37 오후 org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl getIsolatedConnection
INFO: HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@1b11ef33] for (non-JTA) DDL execution was not in auto-commit mode; the Connection 'local transaction' will be committed and the Connection will be set into auto-commit mode.
12월 26, 2021 10:48:37 오후 org.hibernate.tool.schema.internal.ExceptionHandlerLoggedImpl handleException
WARN: GenerationTarget encountered exception accepting command : Error executing DDL "
    create table Member (
       id varchar(255) generated by default as identity,
        name varchar(10),
        primary key (id)
    )" via JDBC Statement
org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL "
    create table Member (
       id varchar(255) generated by default as identity,
        name varchar(10),
        primary key (id)
    )" via JDBC Statement
	at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:67)
	at org.hibernate.tool.schema.internal.SchemaCreatorImpl.applySqlString(SchemaCreatorImpl.java:440)
	at org.hibernate.tool.schema.internal.SchemaCreatorImpl.applySqlStrings(SchemaCreatorImpl.java:424)
	at org.hibernate.tool.schema.internal.SchemaCreatorImpl.createFromMetadata(SchemaCreatorImpl.java:315)
	at org.hibernate.tool.schema.internal.SchemaCreatorImpl.performCreation(SchemaCreatorImpl.java:166)
	at org.hibernate.tool.schema.internal.SchemaCreatorImpl.doCreation(SchemaCreatorImpl.java:135)
	at org.hibernate.tool.schema.internal.SchemaCreatorImpl.doCreation(SchemaCreatorImpl.java:121)
	at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:155)
	at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:72)
	at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:310)
	at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:467)
	at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:939)
	at org.hibernate.jpa.HibernatePersistenceProvider.createEntityManagerFactory(HibernatePersistenceProvider.java:56)
	at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:79)
	at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:54)
	at hellojpa.JpaMain.main(JpaMain.java:12)
Caused by: org.h2.jdbc.JdbcSQLFeatureNotSupportedException: Feature not supported: "CHARACTER VARYING(255)"; SQL statement:

    create table Member (
       id varchar(255) generated by default as identity,
        name varchar(10),
        primary key (id)
    ) [50100-202]
	at org.h2.message.DbException.getJdbcSQLException(DbException.java:556)
	at org.h2.message.DbException.getJdbcSQLException(DbException.java:477)
	at org.h2.message.DbException.get(DbException.java:223)
	at org.h2.message.DbException.get(DbException.java:199)
	at org.h2.message.DbException.getUnsupportedException(DbException.java:287)
	at org.h2.command.ddl.SequenceOptions.getBounds(SequenceOptions.java:313)
	at org.h2.command.ddl.SequenceOptions.getBounds(SequenceOptions.java:244)
	at org.h2.schema.Sequence.<init>(Sequence.java:101)
	at org.h2.table.Column.initializeSequence(Column.java:459)
	at org.h2.command.ddl.CommandWithColumns.generateSequences(CommandWithColumns.java:103)
	at org.h2.command.ddl.CreateTable.update(CreateTable.java:110)
	at org.h2.command.CommandContainer.update(CommandContainer.java:173)
	at org.h2.command.Command.executeUpdate(Command.java:247)
	at org.h2.server.TcpServerThread.process(TcpServerThread.java:413)
	at org.h2.server.TcpServerThread.run(TcpServerThread.java:190)
	at java.base/java.lang.Thread.run(Thread.java:834)

	at org.h2.message.DbException.getJdbcSQLException(DbException.java:507)
	at org.h2.engine.SessionRemote.done(SessionRemote.java:611)
	at org.h2.command.CommandRemote.executeUpdate(CommandRemote.java:237)
	at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:228)
	at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:201)
	at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:54)
	... 15 more

12월 26, 2021 10:48:37 오후 org.hibernate.tool.schema.internal.SchemaCreatorImpl applyImportSources
INFO: HHH000476: Executing import script 'org.hibernate.tool.schema.internal.exec.ScriptSourceInputNonExistentImpl@1eba372c'

Member.java

contact

persistence.xml에서 MySQL 방언으로 다시 실행

contact

AUTO_INCREMENT로 키를 생성하겠다 설정이 된것을 볼 수 있습니다.

H2 1.4.202 버전을 사용하고 있는데, @GeneratedValue(strategy = GenerationType.IDENTITY) 가 적용이 안되고,
ERROR: NULL not allowed for column “ID”; SQL statement: /* insert hellojpa.Member */ insert into Member (id, name) values (null, ?) [23502-200]
오류가 발생하여 검색을 해보니 최신 H2 DB에 버그라고 하네요.

h2 데이터베이스는 꼭 다음 링크에 들어가서 1.4.200 버전을 설치해주세요. 최근에 나온 2.0.202 버전을 설치하면 일부 기능이 정상 동작하지 않습니다

2.0.200 버전으로 다시 설치 하였습니다.

Hibernate: 
    /* insert hellojpa.Member
        */ insert 
        into
            Member
            (id, name) 
        values
            (null, ?)
12월 26, 2021 11:09:52 오후 org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
WARN: SQL Error: 23502, SQLState: 23502
12월 26, 2021 11:09:52 오후 org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
ERROR: NULL not allowed for column "ID"; SQL statement:
/* insert hellojpa.Member */ insert into Member (id, name) values (null, ?) [23502-200]
12월 26, 2021 11:09:52 오후 org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl stop
INFO: HHH10001008: Cleaning up connection pool [jdbc:h2:tcp://localhost/~/test]

Process finished with exit code 0

IDENTITY 전략 애매한점#

strategy = GenerationType.IDENTITY를 사용할 경우 Key를 Null로 하여 DB에 인서트할 당시에 키가 생성하게됩니다.
영속성 컨텍스트에서 관리를 하기 위해서는 PK값이 있어야 합니다. 하지만 이 전략은 DB에 들어가봐야 PK를 알 수 있습니다. 그래서 제약이 생기게 됩니다.

contact

GeneratedValue 전략을 다시 GenerationType.IDENTITY로 바꿔서 테스트 해보겠습니다.

Memeber.java

@Entity
public class Member {

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

JpaMain.java

       System.out.println("----------- 0");

            Member member1 = new Member();
            member1.setUserName("유저A");
            em.persist(member1);
            System.out.println("member1.id : " +member1.getId());

            System.out.println("----------- 1");

            Member member2 = new Member();
            member2.setUserName("유저A");
            em.persist(member2);

            System.out.println("member2.id : " +member2.getId());

            System.out.println("----------- 2");
            tx.commit();

            System.out.println("----------- commit");

contact

persist() 시점에 Insert SQL 이 날라가게 됩니다. 그리고 바로 영속성 컨텍스트의 1차 캐시에 Id 값을 가져올 수 있는 것 을 확인 할 수 있습니다.

GenerationType.SEQUENCE#


GenerationType.SEQUENCE - 특징#

  • 데이터베이스 시퀀스는 유일한 값을 순서대로 생성하는 특별한 데이터베이스 오브젝트( 예) 오라클 시퀀스)
  • 오라클, PostgreSQL, DB2, H2 데이터베이스에서 사용

Member.java
GeneratedValue 전략을 GenerationType.SEQUENCE 로 변경

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private String id;

GeneratedValue(strategy = GenerationType.SEQUENCE) 적용시 오류 발생이 되었고 오류는 아래와 같습니다.


javax.persistence.PersistenceException: org.hibernate.id.IdentifierGenerationException: Unknown integral data type for ids : java.lang.String
	at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:154)
	at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:181)
	at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:188)
	at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:807)
	at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:785)
	at hellojpa.JpaMain.main(JpaMain.java:22)
Caused by: org.hibernate.id.IdentifierGenerationException: Unknown integral data type for ids : java.lang.String
	at org.hibernate.id.IdentifierGeneratorHelper.getIntegralDataTypeHolder(IdentifierGeneratorHelper.java:224)
	at org.hibernate.id.enhanced.SequenceStructure$1.getNextValue(SequenceStructure.java:98)
	at org.hibernate.id.enhanced.NoopOptimizer.generate(NoopOptimizer.java:40)
	at org.hibernate.id.enhanced.SequenceStyleGenerator.generate(SequenceStyleGenerator.java:482)
	at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:119)
	at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:192)
	at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:135)
	at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:62)
	at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:800)
	... 2 more


Caused by: org.hibernate.id.IdentifierGenerationException: Unknown integral data type for ids : java.lang.String

알 수 없는 정수 데이터 유형 : String

Member.java의 Id 가 현재 String이라 나오던 문제였습니다.

Member.java - String Id -> Long Id로 변경

package hellojpa;

import javax.persistence.*;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;

@Entity
public class Member {

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

    @Column(name="name", length = 10) // 엔티티 명은 userName으로, DB 컬럼명을 name으로 매핑하여 사용 지정
    private String userName;


    // JPA 기본적으로 동적으로 객체를 생성하는 기능이 있어, 기본 생성자도 추가해줘야 된다.
    public Member() {
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

}

contact

contact

contact

call next value for hibernate_sequence 기본 시퀀스를 사용해서 새로운 키값을 생성하게 되는데, 테이블 마다 시퀀스를 따로 관리하고 싶다면 @SequnceGenerator를 사용하면 됩니다.

Sequence 전략 - 매핑#

Member.java

@Entity
@SequenceGenerator(
        name = "MEMBER_SEQ_GENERATOR"
        , sequenceName = "MEMBER_SEQ" // 매핑할 데이터베이스 시퀀스 이름
        , initialValue = 1, allocationSize = 1
)

public class Member {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE
            , generator = "MEMBER_SEQ_GENERATOR") //사용할 Generator 매핑
    private Long id;

contact

contact

SEQUENCE - @SequenceGenerator#

  • 주의 allocationSize 기본 값 = 50
속성 설명 기본값
name 식별자 생성기 이름 필수
sequenceName 데이터베이스에 등록되어있는 시퀀스 이름 hibernate_sequence
initialValue DDL 생성 시에만 사용됨, 시퀀스 DDL을 생성할 때 처음 시작하는 수를 1로 지정한다. 1
allocationSize 시퀀스 한 번 호출에 증가하는 수(성능 최적화에 사용됨)
데이터베이스 시퀀스 값이 하나씩 증가하도록 설정되어 있으면 이 값을 반드시 1로 설정해야 한다
50
catalog, schema 데이터베이스 catalog, schema 이름

SEQUENCE - 추가 설명#

GeneratedValue의 전략을 GenerationType.SEQUENCE로 사용하게 되면 sequence를 생성하게 되는데

Hibernate: 
    
    drop table Member if exists
Hibernate: 
    
    drop sequence if exists MEMBER_SEQ
Hibernate: create sequence MEMBER_SEQ start with 1 increment by 1 // 1부터 시작하여, 1씩 증가한다.
Hibernate: 
    

JpaMain.java

   System.out.println("----------- 0");

            Member member1 = new Member();
            member1.setUserName("유저A");
            em.persist(member1);
            System.out.println("member1.id : " +member1.getId());

            System.out.println("----------- 1");

            Member member2 = new Member();
            member2.setUserName("유저A");
            em.persist(member2);

            System.out.println("member2.id : " +member2.getId());

            System.out.println("----------- 2");
            tx.commit();

            System.out.println("----------- commit");

contact

SEQUECE 전략도 영속성 컨텍스트에 저장할 당시 PK 값이 필요하기 때문에,

----------- 0
Hibernate: 
    call next value for MEMBER_SEQ
member1.id : 1
----------- 1

———– 0 과 ———– 1 사이에서 call next value for MEMBER_SEQ 시퀀스 nextVal으로 키값을 받아, 영속성 컨텍스트의 1차 캐시에 이미 id와 userName이 들어간 상태이고 2번째 유저 또한 ———– 1 과 ———– 2 영속성 컨텍스트에 저장됩니다.
이후 commit()을 하게되면 Insert를 하게됩니다.

IDENTITY에서는 안되지만, SEQUENCE에서는 JDBC BATCH를 이용한 버퍼를 이용할 수 있습니다.

contact

이렇게 보다보니 성능에 한번에 인서트 하는게 아니라 seq 얻어올때, Insert 할때 자꾸 DB에 네트워킹을 통해 성능적으로 떨어지는 것 아닌가 싶기도합니다.
그래서 성능 최적화를 위하여 JPA에 allocationSize로 성능을 최적화 하는 방법이 있습니다. 자세한 설명은 뒤에서 하겠습니다.

GenerationType.TABLE#


GenerationType.TABLE - 특징#

  • 키 생성 전용 테이블을 하나 만들어서 데이터베이스 시퀀스를 흉내내는 전략
    장점 : 모든 데이터베이스에 적용 가능
    단점 : 성능

Table 전략 - 매핑#

Member.java

@Entity
@TableGenerator(
        name = "MEMBER_SEQ_GENERATOR"
        , table = "MY_SEQUENCE" // 매핑할 테이블명
        , pkColumnValue = "MEMBER_SEQ" , allocationSize = 1)
public class Member {

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE
            , generator = "MEMBER_SEQ_GENERATOR") //사용할 Generator 매핑
    private Long id;


ctrate table MY_SEQUENCE (
	sequence_name varchar(255) not null,
	next_val bigint,
	primary ket (sequence_name)
)

수정하고 애플리케이션 재시작 하면, JPA가 자동으로 MY_SEQUENCE 테이블을 생성해준다.

contact

contact

contact

@TableGenerator - 속성#

속성 설명 기본값
name 식별자 생성기 이름 필수
table 키 생성 테이블 이름 hibernate_sequences
pkColumnName 시퀀스 컬럼명 sequence_name
valueColumnName 시퀀스 값 컬럼명 next_val
pkColumnValue 키로 사용할 값 이름 엔티티 이름
initalValue 초기 값, 마지막으로 생성된 값이 기준이다. 0
allocationSize 시퀀스 한 번 호출에 증가하는 수 50
catalog, schema 데이터베이스 catalog, schema 이름
uniqueConstains(DDL) 유니크 제약 조건을 지정할 수 있다.

운영에서는 table 전략을 사용하기는 부담스럽고 각 테이블의 sequence를 사용한 sequence 전략을 적극 채용하여 사용한다고 합니다.

권장하는 식별자 생성 전략#


  • 기본 키 제약 조건 : null 아님, 유일, 변하면 안된다.
  • 미래까지 이 조건을 만족하는 자연키를 찾기 어렵다. 대리키(대체키)를 사용하자. ( 비즈니스와 상관없는 랜덤키)
  • 예를 들어 주민등록번호도 기본 키로 적절하지 않다.
  • 권장 : Long형 + 대체키 + 카 생성전략 사용

10억이 넘어도 동작해야 하니까 Long형, 시퀀스를 쓴다던가, uuid를 쓴다던가 대체키를 쓰시고, 카생성 전략들을 조합해서 사용하는 것을 권장
AUTO-INCREMENT나 SEQUENCE Object 둘중 하나를 사용하시고 아니면 때에 따라서 uuid, 랜덤 값을 조합한 회사내의 룰을 따르길 권장.
절대 비즈니스 로직을 키로 끌고 오는것을 권장하지는 않는다고 합니다.

allocationSize를 이용한 성능향상#


allocationSize를 1로 설정하여 1씩 증가하게 세팅을 해두었는데, 기본 값은 50 입니다. 기본 값이 50인 이유는 JPA는 새로운 키 50개를 한번에 만들어 놓고,
DB에 50으로 세팅하고 메모리 상에서 1부터 50 까지 순차적으로 사용합니다. 이후 50개를 모두 사용하면, call next를 하여 51 부터 100까지 미리 만들어 사용합니다.
또 대단한 것이 어떤 DB를 사용해도 이슈 없이 동작한다고 합니다.

@Entity
@SequenceGenerator(
        name = "MEMBER_SEQ_GENERATOR"
        , sequenceName = "MEMBER_SEQ" // 매핑할 데이터베이스 시퀀스 이름
        , initialValue = 1, allocationSize = 50)
public class Member {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE,
                    generator = "MEMBER_SEQ_GENERATOR")
    private Long id;

contact

contact

현재 값은 -1이고 증가는 50 인것을 볼 수 있습니다.

JpaMain.java는 객체 생성 및 persist() 모두 삭제

call next value for MEMBER_SEQ;

위 SQL을 통항 next value를 가져오면 1이 되길 원하는 것입니다.

contact

JpaMain.java

  System.out.println("----------- 0");

            Member member1 = new Member();
            member1.setUserName("유저A");
            em.persist(member1);
            System.out.println("member1.id : " +member1.getId());

            System.out.println("----------- 1");

            Member member2 = new Member();
            member2.setUserName("유저B");
            //em.persist(member2);

            System.out.println("member2.id : " +member2.getId());

            System.out.println("----------- 2");

            Member member3 = new Member();
            member3.setUserName("유저C");
            //em.persist(member3);

            System.out.println("member2.id : " +member2.getId());

            System.out.println("----------- 3");

            tx.commit();

            System.out.println("----------- commit");

contact

처음 call next value for MEMBER_SEQ;를 호출하고 1이면 50개의 키를 메모리로 가져온 것이 아니기 때문에 1번더 호출합니다.

contact

다시 JpaMain에 persist를 추가하여 테스트 해보면

			 System.out.println("----------- 0");

            Member member1 = new Member();
            member1.setUserName("유저A");

            System.out.println("----------- 1");

            Member member2 = new Member();
            member2.setUserName("유저B");


            System.out.println("----------- 2");

            Member member3 = new Member();
            member3.setUserName("유저C");



            System.out.println("----------- 3");

            em.persist(member1); // call next value for MEMBER_SEQ; DB SEQ = 1  , Key = 1
            em.persist(member2); // call next value for MEMBER_SEQ; DB SEQ = 51 , Key = 2
            em.persist(member3); //                         memory; DB SEQ = 51 , Key = 3


            System.out.println("----------- 4");

            tx.commit();

            System.out.println("----------- commit");

contact

allocationSize를 크게 잡아 메모리에 두고 사용할 수 있지만, 애플리케이션이 내려가게 되면 사용하지 않았던 Id 값들의 구멍이 생겨 낭비가 될 수 있기 때문에 50 ~ 100 정도가 적당합니다.

Table 전략 또한 동일하며, 테이블의 데이터를 미리 설정한 값 만큼 미리 세팅하고 키를 메모리에서 생성하여 사용합니다. 물론 서버가 여러대인 경우에도 서버 각각 중복되지 않고 호출한 순서대로 1~50
, 50 ~100 씩 할당받아 메모리에 키를 두고 사용합니다. 때문에 동시성 문제가 발생하지 않고 문제없이 동작합니다.

참고- 자바 ORM 표준 JPA - 김영한#