@Entity 클래스에는 기본적으로 PK(PrimaryKey)가 있어야 한다.
PK로 사용할 칼럼에 @Id 어노테이션을 사용하여 해당 칼럼을 PK로 설정한다.
이 PK 매핑 방법과 여러 가지 속성들에 대해 알아보자.
PrimaryKey Mapping
기본적으로 @Id 어노테이션은 꼭 필요하다.
여기에 자동 생성을 위한 @GeneratedValue 어노테이션을 붙일 수 있다.
PrimaryKey를 사용자가 설정하는 userId 등으로 설정할 때는 @Id 어노테이션만 사용하면 되고,
ID를 임의의 값으로 순차적으로 증가시킬 때는 @GenaeratedValue 어노테이션을 추가하면 된다.
Key 자동 할당
Key를 자동 할당하는 방법에는 IDENTITY, SEQUENCE, TABLE, AUTO 가 있다.
Key 자동 생성 시에는 해당 Entity의 PK로 설정한 필드에 아무 값도 설정하지 않고 DB에 저장해야 한다.
IDENTITY
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
기본 키 생성을 데이터베이스에 위임한다.
Member member = new Member();
member.setName("hello");
em.persist(); //insert 쿼리 -> member에 id 값 세팅
Long id = member.getId(); //id값을 알 수 있다.
JPA에서는 IDENTITY 전략을 사용했을 때,
새로운 엔티티를 DB에 저장 시 즉시 insert 쿼리가 나가고, 자동 생성된 id 값을 확인할 수 있다.
원래는 em.persist()를 해도 쿼리가 바로 DB에 적용되지 않는 쓰기 지연이 JPA의 특징이지만,
IDENTITY 전략 사용시에는 즉시 insert 쿼리가 DB에 적용된다.
그러나 이 때문에 유의미한 성능 차이가 발생하지는 않는다고 한다.
SEQUENCE
@SequenceGenerator(
name = "member_seq_generator",
sequenceName = "member_seq",
initialValue = 1,
allocationSize = 50)
@Entity
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "member_seq_generator")
private Long id;
}
시퀀스는 순서를 뜻하는 것으로 유일한 값을 순서대로 생성하는 것이다.
특정 데이터베이스에는 유일한 값을 생성해 주는 시퀀스라는 오브젝트가 존재한다.
해당 오브젝트로부터 PK로 사용할 유일한 값을 받아서 사용하는 것이다.
Member member = new Member();
member.setName("hello");
em.persist(); //sequence 테이블에서 다음 id 값 불러와서 member 객체에 id 세팅
// insert 쿼리는 나가지 않음.
Long id = member.getId(); //id값을 알 수 있다.
IDENTITY 전략과 유사하지만,
SEQUENCE 전략일때는 DB의 시퀀스 테이블에서 값을 저장하지만 insert 쿼리는 나가지 않는다.
@SequeceGenerator의 속성
- name : id 필드에 붙은 @GenerateValue의 generator 이름과 매칭된다.
- sequenceName : DB에 생성될 시퀀스 테이블의 이름이다.
- initialValue : 시퀀스 시작 값
- allocationSize : 시퀀스 테이블에서 한 번에 받아올 시퀀스 사이즈 (아래에서 자세히 다룬다.)
TABLE
@TableGenerator(name = "member_seq_generator",
table = "MY_SEQUENCES",
pkColumnValue = "MEMBER_SEQ",
allocationSize = 1)
@Entity
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = "member_seq_generator")
private Long id;
}
키 생성 전용 테이블을 하나 만들어서 데이터베이스 시퀀스를 흉내 내는 전략이다.
- 장점 : 모든 데이터베이스에 적용 가능
- 단점 : 성능이 DB 자동 생성에 비해 안 좋다.
AUTO
IDENTITY 전략과 유사하지만, 각 데이터베이스 방언에 따라 해당 데이터베이스의 기본 PK 생성 전략을 따른다.
ex) sequence : oracle, PostgreSQL, H2 등
SEQUENCE와 TABLE 전략의 성능 개선 방법
위의 예제에서 SEQUENCE 전략일 때는 DB의 시퀀스 테이블에서 다음 값을 불러와서 사용한다고 했다.
이렇게 하면 객체를 한번 저장할 때 마다 DB에 접근해야 하는 문제가 있다.
이 문제를 해결하기위해 allocationSize라는 개념을 도입해서 DB 접근 횟수를 줄인다.
allocationSize 속성
allocationSize = {size}를 설정하면 DB의 시퀀스 테이블의 값을 {size}만큼 증가시키고 해당 {size}만큼의 시퀀스가 증가되는 동안은 메모리 환경에서 해당 값을 관리한다.
(ex)
initialValue = 1, allocationSize = 50일 경우
맨 처음 엔티티를 추가할 때, id =1로 설정하고 DB의 시퀀스 테이블의 다음 값은 51로 변경된다.
이후 다음 49번 동안은 엔티티를 추가할 때 DB의 시퀀스 테이블에 접근하지 않고 메모리에서 값을 증가시켜서 사용한다.
이 방법 덕분에 매번 시퀀스 테이블에 접근하는 성능 낭비를 줄일 수 있게 된다.
TABLE 전략도 initialValue, allocationSize가 SEQUENCE 전력과 동일하게 적용된다.
동시성 문제
이 방법을 사용했을 때 동시성 문제는 발생하지 않는다.
A에서 시퀀스 테이블의 값을 실제로 증가시키고, 1~50번을 사용한다면, 50번까지는 그 순간 비어있게 되기 때문에
B에서 시퀀스 테이블에 접근할 때는 다시 51~100번을 사용하게 된다.
실제 DB 접근은 맨 처음 한 번씩만 일어나기 때문에 동시성 문제는 걱정하지 않아도 된다.
(참고) 인프런 - 김영한 님 '자바 ORM 표준 JPA 프로그래밍 - 기본 편'
https://www.inflearn.com/course/ORM-JPA-Basic
'Database > JPA' 카테고리의 다른 글
[JPA] 연관관계 매핑 - @ManyToOne, @OneToMany (0) | 2023.10.06 |
---|---|
[JPA] @Entity - 필드와 컬럼 매핑의 여러가지 속성 (1) | 2023.10.04 |
[JPA] 엔티티 매핑 (0) | 2023.10.04 |
[JPA] ORM, JPA, Hibernate, Spring Data JPA의 관계 (0) | 2023.10.03 |
[JPA] 영속성 컨텍스트의 주요 개념 / Spring Data JPA에서의 영속성 (1) | 2023.10.02 |