JAVA/JPA

기본키 생성 전략 @GeneratedValue

호두밥 2022. 2. 11. 23:30

@Id

@Entity에 기본키 칼럼을 선언하려면 @Id를 사용합니다. 

기본키를 직접 할당하려면 @Id만 적어준 뒤 코드에서 직접 set을 해주면 됩니다. 데이터베이스에서 자동으로 생성하게 하려면 @GeneratedValue를 사용해야 합니다.

@GeneratedValue는 IDENTITY, SEQUENCE, TABLE 3가지 방식이 있습니다. 원하는 방식을 @GenerateValue의 strategy 속성으로 입력해줍니다. 

strategy 속성을 적지 않고 @GeneratedValue만 쓰면 GenerationType.AUTO가 적용되고, JPA에서 데이터베이스에 맞는 자동생성 전략을 선택합니다. (MYSQL은 IDENTITY, 오라클은 SEQUENCE)

@Entity
public class Customer{
	@Id
	@GeneratedValue
	private Long id;
    private String name;
}

 

GenerationType.IDENTITY

IDENTITY는 기본키 생성을 데이터베이스에게 모두 맡겨버리는 방식입니다. MySql, PostgreSQL, SQL Server 등에서 사용합니다. 

IDENTITY로 설정하면, MYSql은 기본키에 AUTO_INCREMENT 조건을 설정합니다. 그러면 데이터베이스에서 1부터 순차적으로 1씩 증가하는 기본키를 생성해줍니다. 

CREATE TABLE CUSTOMER (
	ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    NAME VARCHAR(20)
);
@Entity
public class Customer{
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long id;
    private String name;
}

IDENTITY 전략을 사용하면 객체를 생성, 또는 저장한 뒤 ID값을 가져오기 위해 데이터베이스를 추가로 조회하는 작업을 합니다. 

Customer customer = new Customer("manta");
em.persist(customer);
System.out.printIn("customer.getId() = " + customer.getId())
customer.getId() = 1

 

GenerationType.SEQUENCE

SEQUENCE는 지정한 규칙에 따라 값이 일정하게 증가하는 데이터베이스 오브젝트입니다. 예를 들어 1000부터 3씩 증가한다는 규칙을 시퀀스로 생성할 수 있습니다. 이 전략은 시퀀스를 지원하는 오라클, PostgreSQL등에서 사용합니다. 

generator 속성으로 사용할 시퀀스 오브젝트 이름을 기입해주어야 합니다.

CREATE SEQUENCE customers_seq
 START WITH     1000
 INCREMENT BY   1
 NOCACHE
 NOCYCLE;

 * CREATE SEQUENCE, ORACLE

@Entity
@SequenceGenerator(
	name="customers_seq", sequenceName="customers_seq", initialValue=100, allocationSize=1
)
public class Customer {
    
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "customer_seq")
    private Long id;
}

* 시퀀스를 jpa에서 생성해주려면 @SequenceGenerator를 사용합니다. 

SEQUENCE 전략은 IDENTITY와 반대로,  데이터베이스에서 식별자를 조회하여 엔티티에 할당합니다. 엔티티는 영속성 컨텍스트에 저장되고, 트랜잭션 커밋이 일어날 때 엔티티가 데이터베이스에 저장됩니다. 

 

GenerationType.TABLE

TABLE은 채번테이블을 사용하는 전략입니다. 모든 데이터베이스에서 사용할 수 있습니다. 

@TableGenerator를 사용해 사용할 채번 전략을 조회(설정)합니다. 

@Entity
@TableGenerator(name = "customer_seq", table = "seq_table", 
	pkColumnName = "name",
	valueColumnName = "value",
	pkColumnValue="task_gen",
	initialValue=1000, 
	allocationSize=10)
public class Customer {    
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE, generator = "customer_seq")
    private Long id;
}
속성명 설명
name 채번 전략 이름, @GeneratedValue의 generator 속성에 name값을 넣어줍니다. 
table 채번 전략 정보가 저장되어 있는 테이블명 (채번 테이블)
pkColumnName 채번 테이블의 pk 칼럼 명
valueColumnName 시퀀스 값 (max, 최종값) 칼럼 명
pkColumnValue 채번 규칙을 조회할 key (채번 전략 ID)
initialValue 초기값, 마지막으로 생성된 값이 기준
allocationSize 시퀀스 한 번 호출에 증가하는 수
   

 

TABLE 전략은 시퀀스 값을 조회하기 위해 SELECT를, 다음 값으로 증가시키기 위해 UPDATE를 발생시킵니다. 때문에 다른 전략에 비해 데이터베이스와의 통신횟수가 많습니다. 또 테이블을 사용하기 때문에, 트랜잭션이 끝날 때까지 테이블에 LOCK이 걸리는 등의 성능이슈가 발생할 수 있습니다.

TABLE 전략에서 성능이슈를 해결하기 위해서 사용하는 설정값이 allocationSize 입니다. 예를들어 allocationSize가 10이라면, 시퀀스가 한번 호출된 후 트랜잭션 내부에서 Entity를 10개를 생성하는 동안 (seq_nbr이 10까지 늘어나는 동안),  채번 테이블을 select하고 update하는 동작이 일어나지 않게 됩니다. 10을 넘어가게 되면, 다시 채번 테이블을 조회합니다. 

Customer customerA = new Customer("aaa");
Customer customerB = new Customer("bbb");
Customer customerC = new Customer("ccc");

* allocationSize = 10, 이므로 고객을 3명 생성하지만 채번 테이블은 처음에 1번만 조회하고 update 합니다.

 

참고자료

 

'JAVA > JPA' 카테고리의 다른 글

[Querydsl] fetch 결과 조회  (0) 2022.03.25