@Id
데이터베이스 테이블의 기본 키(PK)와 객체의 필드를 매핑시켜주는 역할을 수행한다.
@Id만 사용할 경우 기본 키를 직접 할당해 주어야 한다. 기본 키를 직접 할당하는 방법 대신 데이터베이스가 생성해주는 값을 사용하려면 @GeneratedValue를 붙여주면 된다.
적용이 가능한 타입
- 자바 기본형 (int, long, ...)
- 자바 래퍼형 (Integer, Long, ...)
- String
- Date (java.util)
- Date (java.sql)
- BigDecimal
- BigInteger
@GeneratedValue
기본 키를 자동으로 생성시켜주는 역할을 수행한다.
속성으로는 strategy가 있으며, 이를 통해 자동 생성 전략을 설정할 수 있다.
속성값 | 설명 | 대표 DBMS |
strategy = GenerationType.IDENTITY | 기본키 생성을 데이터베이스에 위임. | MYSQL |
strategy = GenerationType.SEQUENCE | 시퀀스 사용, @SequenceGenerator 필요(시퀀스 생성) | ORACLE |
strategy = GenerationType.TABLE | 키 생성용 테이블 사용, @TableGenerator 필요 | 모든 DBMS |
strategy = GenerationType.AUTO | 데이터베이스 방언에 따라 자동 지정(기본값) |
IDENTITY 전략
@GeneratedValue(strategy = GenerationType.IDENTITY)
IDENTITY 전략은 기본 키 생성을 데이터베이스에 위임하는 전략이다.
주로 MySQL, PostgreSQL, SQL Server, DB2에서 사용한다.
MySQL의 auto_increament의 기능과 방식이 유사하며, 데이터베이스에 값을 저장하고 나서야 기본 키 값을 알 수 있다.
엔티티가 영속 상태가 되기 위해서는 식별자 즉, 기본 키를 가지고 있어야 한다. 하지만 IDENTITY 전략을 사용하면 식별자를 데이터베이스에 저장하기 전까지 알 수 없기 때문에 em.persist()를 하는 즉시 INSERT SQL문이 데이터베이스에 반영되고 데이터베이스에서 식별자를 조회한다. 따라서 IDENTITY 전략은 트랙잭션을 지원하는 쓰기 지연이 동작하지 않는다.
SEQUENCE 전략
@GeneratedValue(strategy = GenerationType.SEQUENCE)
SEQUENCE 전략은 ORACLE의 sequence 처럼 유일한 값을 순서대로 생성한다.
이 전략은 sequence를 지원하는 ORACLE, PostgreSQL, DB2, H2에서 사용할 수 있다.
@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"
)
@Column(name = "MEMBER_ID")
private Long id;
...
}
SEQUENCE 전략을 사용하기 위해서는 우선 사용할 데이터베이스 시퀀스를 매핑해야 한다.
@SequenceGenerator를 사용하여 시퀀스 생성기를 등록한 후, @GeneratedValue의 generator 속성으로 시퀀스 생성기를 선택한다.
@SequenceGenerator 속성
속성 | 설명 | 기본값 |
name | 식별자 생성기 이름 |
필수 |
squenceName | 데이터베이스에 등록되어 있는 시퀀스 이름 | hibernamte_sequnce |
initialValue | DDL 생성 시에만 사용됨, 시퀀스 DDL을 생성할 때 처음 1 시작하는 수를 지정한다. | 1 |
allocationSize | 시퀀스 한 번 호출에 증가하는 수 (성능 최적화에 사용) 데이터베이스 시퀀스 값이 하나씩 증가하도록 설정되어 있으면 이 값을 반드시 1로 설정해야 한다 |
50 |
catalog, shema | 데이터베이스 catalog, schema 이름 |
allocationSize의 작동방법
- 최초 persist() 호출시 데이터베이스의 시퀀스 nextValue를 두번 호출하여 시작값과 끝값을 가져온다.
- 어플리케이션에서 시작값이 끝값이 될때까지 시퀀스를 메모리에서 할당해준다.
- 시퀀스를 끝값까지 전부 사용하게 되면 다시 시퀀스를 호출하는데, 여기서 JPA는 allocationSize를 보고 다음 시작값을 계산한다. 끝 값 = 현재 값 + allocationSize, 시작 값 = 끝 값 - (allocationSize - 1)
- 2번과 3번을 반복한다.
allocaitionSize 설정시 주의할 점
allocaitionSize의 기본값은 50이다. 그런데 만약 실제 데이터베이스의 시퀀스 증가값은 1일때 어떤 일이 벌어질까? 위의 작동 방법대로면, 3번 동작 즉, 두번째 시작 값을 계산 할 때 시작 값이 음수가 된다. 그리고 시작값부터 시퀀스가 계속 할당되고 끝값으로 가게되면 언젠가는 이미 존재하는 시퀀스를 참조하게 되어 에러가 발생하게 된다.
고로, allocaitionSize를 설정할때는 실제 데이터베이스의 증가값을 고려하여 시작값이 음수가 되지 않게 고려하며 성능 최적화를 해야한다.
이해가 안되면 설명을 깔끔하게 해주신 분에게 도움을 받자...
[JPA] 식별자 할당 SEQUENCE(시퀀스) 사용 전략
JPA 식별자 JPA는 엔티티들을 논리적인 공간인 영속성 컨텍스트에서 관리하는데, 엔티티를 구분할 수 있는 식별자가 필요합니다. 식별자가 되는 필드는 엔티티 클래스의 @Id 애노테이션을 통해 지
dololak.tistory.com
IDENTITY와 SEQUENCE의 차이점
두 전략이 식별자 값을 얻기 위해 DB에 접속하는 것이 비슷해 보이지만 차이점이 있다.
서로 플러시가 발생하는 시점이 다르다.
- IDENTITY 전략은 em.persist() 시점에 쓰기 지연을 하지 않고, 쿼리를 바로 날려 데이터베이스에 데이터를 저장하고, 식별자를 조회한 후 영속성 컨텍스트에 저장된다.
- 시퀀스 전략은 em.persist() 시점에 시퀀스를 조회하는 쿼리를 DB에 날려 시퀀스의 nextValue를 받고 식별자를 조회한다. 그리고 조회한 식별자를 엔티티에 할당한 후, 영속성 컨텍스트에 저장된다. 이후 트랜잭션 commit 시점에 플러시가 발생하여 데이터베이스에 저장한다.
TABLE 전략
@GeneratedValue(strategy = GenerationType.TABLE)
TABLE 전략은 키 생성 전용 테이블을 하나 만들고, 이름과 값으로 사용할 컬럼을 만들어 데이터베이스 시퀀스를 흉내내는 전략이다. 따로 @TableGenerator 설정이 필요하다.
이 전략은 테이블을 사용하기 때문에, 시퀀스를 지원하지 않는 데이터베이스에서도 사용할 수 있는 이점이 있다. 그러나 성능 때문에 권장되는 방식은 아니다.
@Entity
@TableGenerator(
name = "MEMBER_SEQ_GENERATOR",
table = "MY_SEQUENCE",
pkColumnValue = "MEMBER_SEQ",
initialValue = 1,
allocationSize = 50
)
public class Member {
@Id
@GeneratedValue(
strategy = GenerationType.TABLE,
generator = "MEMBER_SEQ_GENERATOR"
)
@Column(name = "MEMBER_ID")
private Long id;
...
}
SEQUENCE 전략과 매우 흡사하며, 시퀀스 대신 테이블을 사용하는 것 이외에는 내부 동작 방식이 동일하다.
@TableGenerator 속성
속성 | 기능 | 기본값 |
name | 식별자 생성기 이름 | 필수 |
table | 키 생성 테이블 명 | hibernate_squences |
pkColumnName | 시퀀스 칼럼 명 | hibernate_name |
valueColumnName | 시퀀스 값 컬럼명 | next_val |
pkColumnValue | 키로 사용 할 값 이름 | 엔티티 이름 |
initialValue | 초기값, 마지막으로 생성된 값이 기준 | 0 |
allocationSize | 시퀀스를 한번 호출할 때 증가하는 수 (성능 최적화에 사용된다.) |
50 |
catalog, schema | 식별자 생성기의 catalog, schema 이름 | |
uniqueConstraints (DDL) | 유니크 제약 조건을 지정할 수 있다. |
AUTO 전략
@GeneratedValue(strategy = GenerationType.AUTO)
데이터베이스는 종류도 많고 기본 키를 만드는 방법도 다양하다. AUTO로 설정하면 데이터베이스 방언에 따라 IDENTITY, SEQUENCE, TABLE 전략 중 하나를 자동으로 선택하게 된다.
@GeneratedValue의 속성 strategy을 생략할 경우 기본 값은 AUTO로 설정된다.
만약 AUTO를 사용할 때 SEQUENCE나 TABLE 전략이 선택되면, 시퀀스나 키 생성용 테이블을 미리 만들어 두어야 한다.
스키마 자동 생성 기능(ddl-auto)을 사용한다면, 하이버네이트가 기본값을 사용해서 적절하게 만들어준다.
Reference
자바 ORM 표준 JPA 프로그래밍 - 기본편 - 인프런 | 강의
JPA를 처음 접하거나, 실무에서 JPA를 사용하지만 기본 이론이 부족하신 분들이 JPA의 기본 이론을 탄탄하게 학습해서 초보자도 실무에서 자신있게 JPA를 사용할 수 있습니다., - 강의 소개 | 인프런
www.inflearn.com
'Spring > JPA' 카테고리의 다른 글
[JPA] 연관관계 편의 메서드 (0) | 2023.01.10 |
---|---|
[JPA] @JoinColumn과 연관관계 주인(mappedBy) (0) | 2023.01.10 |
[JPA] 엔티티 매핑 - 필드와 컬럼 매핑 (0) | 2022.12.27 |
[JPA] hibernate.ddl-auto 설정 (0) | 2022.12.27 |
[JPA] 엔티티 매핑 - 객체(Entity)와 테이블(Table) 매핑 (0) | 2022.12.27 |