# JPA 기본키 매핑 전략

JPA의 기본 키 매핑을 하는 방법은 annotation을 사용하면 된다.

  • @Id
  • @GeneratedValue
    이렇게 두개의 annotation을 사용해주면 된다.

@Id만 사용하여 로직에서 생성되는 Id를 직접 할당해주는 방법이 있고, @GeneratedValue를 추가하여 자동으로 생성해주는 방법이 있다.

# 직접할당

직접할당 방법은 말그대로 직접 Id값을 넣어주는 방법이다. DB에서 Primary Key 조건은 null이 아니고, 유일해야하며 변하면 안된다. 비즈니스에서 어떤 값을 id로 설정을하게 된다면 변하지 않아야한다는 조건을 지키기가 굉장히 힘들것이다. 따라서 대체로 의미없는 특정 값을 넣어 Id로 사용하는 것이 바람직하며 이를 DB가 자동생성해줄 수 있다.

# 자동생성

자동생성은 @GeneratedValue 어노테이션을 사용해주면된다. @GeneratedValue는 4가지 전략이 있다.

  • IDENTITY
  • SEQUENCE
  • TABLE
  • AUTO

# IDENTITY

@Entity
public class Member{
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long id;
}
1
2
3
4
5
6

IDENTITY 전략은 기본키를 생성하는 것을 DB에게 작업을 넘겨주는 것이다. AUTO_INCREMENT라고하여 1씩 DB에서 증가시켜 넣어주며 INSERT SQL이 실행되는 시점에 ID를 넣어주게 된다.. 영속성 컨텍스트에서 객체를 엔티티로 관리받기 위해서는 Key값이 필수였다. 하지만 이 방법을 사용하면 처음에 key값을 알 수 없다. 따라서 영속성 컨텍스트에서 관리를 하기 위해서 INSERT SQL을 Entity Manager가 persist하자마자 날려주게 된다.(즉 버퍼링으로 모아서 Insert 불가)

# SEQUENCE

데이터베이스 시퀀스는 유일한 값을 순서대로 생성하는 특별한 DB의 Object를 의미한다. 이렇게 DB에서 시퀀스를 생성해서 넘겨주면 이것을 받아서 Id로 사용하는 전략이다.

@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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13

이렇게 Sequence Generator로 시퀀스를 생성해서 사용해준다. 만약 객체를 생성하여 persist해주면, DB에 있는 시퀀스 오브젝트를 불러 Id값을 가져온다. 따라서 INSERT SQL을 추후 트랜잭션이 커밋되는 상황에서 함께 날릴 수 있다. 문제는 DB에 항상 가서 Id값을 가져와야한다는 것이다. 이것을 방지하기 위하여 _allocationSize _를 정하여 해당 값만큼을 미리 당겨온다. 예를들어 이 값이 50이면 처음 1부터 생성할때 두번 DB에 방문하여(처음에 1 다음에 50더한 값) 51을 가져오고, 계속 persist되면서 더해진 객체의 ID가 51이 될 때 다시 DB에 가서 값을 세팅하는 과정을 거친다. 이렇게 되면 DB에 접근하는 횟수를 줄일 수 있어 성능적으로 도움을 받을 수 있다. 동시성 문제를 고민할 필요 없이 사용할 수 있다. (만약 1번 서버가 1 ~ 50 구간을 사용하는데 2번 서버가 insert를 요청하면 51 ~ 101을 사용하도록 조치하여 넘겨주기 때문)

# TABLE

키를 생성하는 전용 테이블을 하나 생성해 DB의 시퀀스를 흉내내는 방법이다. 모든 DB에 적용이 가능하지만 성능에 대한 이슈가 있어 사용함에 있어 굉장히 부담스럽다.

create table MY_SEQUENCES(
	sequence_name varchar(255) not null,
	next_val bigint,
	primary key ( sequence_name)
)
1
2
3
4
5

이렇게 위에 처럼 테이블을 하나 생성하여 이 테이블을 키 값처럼 사용하는 것이다. 시퀀스 제너레이터를 사용하였듯이 테이블 제너레이터를 사용한다.

@Entity
@TableGenerator(
	name = "MEMBER_SEQ_GENERATOR",
	table = "MY_SEQUENCES",
	pkColumnValue = "MEMBER_SEQ", allocationSize = 1)
)
public class Member{
	@Id
	@GeneratedValue(strategy = GenerationType.TABLE,
				generator = "MEMBER_SEQ_GENERATOR")
	private Long id;
}
1
2
3
4
5
6
7
8
9
10
11
12

여기서 설명하는 allocationSize는 위에서 말한 것과 동일하다. 보통 50~100정도가 적당하다고 한다.

# AUTO

AUTO는 위 3개의 기능중에 하나를 자동으로 골라주는 전략이다.(DB의 방언을 고려해서 판단)