JPA 가 제공하는 DB 기본 키 할당 전략은 직접 할당 방식과 자동 생성 방식 두 가지가 있다.
직접 할당은 컬럼에 @Id 만 사용하여 생성하는 방식이 있고,
@Id가 적용 가능한 Java Type은 아래와 같다.
- Java 기본형(int, double, long ...)
- Java Wrapper 형
- String
- java.util.Date
- java.sql.Date
- java.math.BigDecimal
- java.math.BigInteger
해당 전략은 em.persist()로 Entity를 저장 하기 전,
Application에서 직접 기본 키를 할당해주어야 한다.
EntityManagerFactory emf = Persistence.createEntityManagerFactory("JPA");
EntityManager em = emf.createEntityManager();
User user = new User();
user.setName("gillog");
user.setId(1);
em.persist(user);
자동 생성은 @Id와 @GeneratedValue를 같이 사용하여 생성하는 방식이 있다.
@GeneratedValue에는 4가지 전략이 있다.
IDENTITY
@Id
@Column(unique = true)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
- 기본 키 생성을 DB에 위임하는 전략이다.
- auto_increment 기능을 제공 해 준다.
- 기본 키 값을 자동으로 생성하는 DBMS에서 사용한다.
- MYSQL, PostgreSQL, SQL Server, DB2에서 사용
JPA에서는 트랜잭션 commit 시점에 insert SQL을 실행한다.
그 직전까지 SQL저장소에 insert 문을 모아 두었다가 flush()가 호출될 때 DB에 접근해서 모든 SQL문을 전달한다.
이때 기본 키를 참조하는 로직이 있거나, 영속성 객체를 만들 때 문제가 생길 수 있다.
hibernate에서는 이를 위한 최적화 방법을 제공한다. hibernate는 JDBC3에 추가된 Statement.getGeneratedKeys() 메서드를 이용해서 데이터를 저장함과 동시에 생성된 기본 키 값을 바로 건져온다. 이를 통해 hibernate는 데이터베이스와 2번 통신(먼저 저장, 이후 id얻어 옴)해야 할 것을 1번만 통신할 수 있게 최적화했다.
여담으로, 공식 문서에 따르면 hibernate 5.3 버전에서는 AUTO전략이 아닌 경우에 엔티티 생성 시 Insert 쿼리를 쓰기 지연하려고 했는데, IDENTITY나 SEQUENCE전략을 따르는 엔티티들이 연관관계(@OneToMany 등)로 묶여 있는 다른 엔티티들과 같은 트랜잭션에 있을 때 문제를 발생시킬 수 있다고 한다.
그래서 hibernate는 5.4버전부터 내부적 알고리즘을 사용하여 Insert쿼리에 쓰기 지연을 해야 하는지 아니면 바로 데이터베이스에 쿼리를 보내야 하는지를 판단하게 했다. 혹시나 5.3버전의 방침인, Insert쿼리에 쓰기 지연이 적용되는 것 때문에 문제가 발생하면 설정에 hibernate.id.disable_delayed_identity_inserts=true 를 명시해 놓으면 Insert시 쓰기 지연이 동작하지 않게(Insert쿼리들이 바로 데이터베이스에 전달되어 엔티티들이 생성 즉시 저장되도록) 할 수 있다.
SEQUENCE
@Entity
@SequenceGenerator(name = "USER_SEQ_GENERATE"
, sequenceName = "USER_SEQ"
, initialValue = 1
, allocationSize = 1)
public class User {
@Id
@Column(unique = true)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "USER_SEQ_GENERATE")
private Long id;
@Column
private String name;
}
- 유일한 값을 순서대로 생성하는 특별한 데이터베이스 오브젝트
속성 | 설명 | 기본값 |
name | 식별자 생성기 이름 | 필수 |
sequenceName | 데이터베이스에 등록되어 있는 시퀀스 이름 | hibernate_sequence |
initialValue | DDL 생성 시에만 사용, 시퀀스 DDL을 생성할 때 처음 시작하는 수를 지정한다. | 1 |
allocationSize | 시퀀스 호출시 증가하는 수(성능 최적화에 사용), 데이터베이스 시퀀스 값이 하나씩 증가하도록 설정되어 있으면 이 값을 반드시 1로 설정해야 한다. | 50 |
catalog, schema | 데이터베이스 catalog, schema 이름 |
hibernate는 데이터베이스 시퀀스 오브젝트에 접근하는 횟수를 줄이기 위해 allocationSize 라는 옵션을 만들어 두었다. 여기에 설정한 값 만큼 데이터베이스에서 한 번에 시퀀스를 받아오고 그 값을 메모리에 저장해 둔다. 이후 새로운 엔티티가 영속 컨텍스트에 추가될 때마다 메모리에서 식별자 값을 가져와서 할당하는 것이다.
allocationSize 를 1로 주었다면 엔티티 생성시마다 데이터베이스에 접근할 것이고, 50으로 주었다면 1번 데이터베이스에 접근해서 1~50을 받아온 뒤 메모리에 저장해 두고, 50번째의 엔티티가 생성될 때 까지 데이터베이스 대신 메모리에서 식별자를 할당해 주는 방식인 것이다. 내 프로그램에서 Insert 쿼리의 성능이 매우 중요한 상황이라면 값을 비교적 크게, 그렇지 않다면 1로 주면 된다.
AUTO
@GeneratedValue(strategy = GenerationType.AUTO)
- AUTO는 hibernate가 DB 방언에 따라 자동으로 IDENTITY, SEQUENCE, TABLE 전략을 자동으로 선택한다.
- 기본 전략이 AUTO로 설정되어 있는데, 만약 SEQUENCE나 TABLE전략이 선택되면 해당 시퀀스나 키 생성용 테이블을 미리 만들어 놓아야 한다.
TABLE
- 키 생성 전용 테이블을 생성해서 키 값을 관리한다.
- 최적화 되지 않은 테이블에서 키를 생성하기 때문에 성능상의 이슈가 발생할 수 있다.
- 잘 사용하지 않는 듯 하다.
[JPA] 기본 키 생성 전략(IDENTITY, SEQUENCE, TABLE)
자바 ORM 표준 JPA 프로그래밍JPA가 제공하는 DB 기본 키 할당 전략은 직접 할당 방식, 자동 생성 방식 두 가지이다.이 중 직접 할당 방식은 Application에서 기본 키를 직접 할당하는 방식이다.자동 생
velog.io
참고 - https://velog.io/@strawberry/JPA-%EA%B8%B0%EB%B3%B8-%ED%82%A4-%EB%A7%A4%ED%95%91
JPA 기본 키 매핑 전략(identity, sequence, auto)
그동안 springboot2 로 수많은 엔티티들을 만들면서 수많은 기본 키를 생성했었다. 하지만 기본 키 생성에 관한 심도있는 고민이 없었다는 생각이 들어서 공부했던 내용을 간단히 정리해 볼까 한다
velog.io
'개발 > Spring' 카테고리의 다른 글
[Spring] @ComponentScan, @EnableJpaRepositories, @EntityScan (0) | 2022.03.04 |
---|---|
[Spring] @transactional 동작 원리 (0) | 2022.02.23 |
[Spring] JPA 복합 키 생성 (@Embeddable, @IdClass) (0) | 2022.02.22 |
[Spring] JPA 잠금(Lock) 이해하기 (0) | 2022.02.15 |