4. 엔티티 매핑 - (4.4 기본 키 매핑)

HotFried·2023년 9월 25일
0

직접 할당

@ID만 사용


자동 생성

@GeneratedValue 추가

IDENTITY

  • 기본 키 생성을 데이터베이스에 위임한다.
    - 주로 MySQL, PostgreSQL, SQL Server, DB2에서 사용한다.
    (ex. MySQL의 AUTO_INCREMENT)
@Entity
public class Member {
	@Id
    @GeneratedValuse(strategy = GenerationType.IDENTITY)
    private Long id;
...

JPA는 보통 트랜잭션 커밋 시점에 INSERT SQL을 실행한다.

IDENTITY 전략의 Id 값은 DB에 insert 쿼리로 데이터가 추가되어야 알 수 있다.
But, 영속상태인 Entity의 ID값을 알 수 없다.
(아직 DB에 insert 쿼리가 나가지 않았기 때문)

=> 울며 겨자먹기로, em.persist(member)시점에 insert 쿼리가 날아간다.
(IDENTITY 전략을 이용할 때는 쿼리를 버퍼처럼 모아서 한번에 날리는 것이 불가능하다.)

Member member = new Member();

System.out.println("====================");
em.persist(member);
System.out.println("member.id  = " + member.getId());
System.out.println("====================");
====================
Hibernate:
	/* insert hellojpa.Member
    	*/ insert
        into
        	Member
            (id, name)
        values
        	(null, ?)
member.id = 1
====================

persist()시점에 insert 쿼리가 날아가는 것을 확인 할 수 있다.

member.getId() 조회 시점에는 select 쿼리가 날아가지 않는다.
(JDBC 드라이버에 insert 쿼리 직후 바로 리턴 받을 수 있는 기능이 있기 때문이다.)


SEQUENCE

  • 데이터베이스 시퀀스는 유일한 값을 순서대로 생성하는 특별한 데이터베이스 오브젝트
@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") 
 	private Long id;

데이터베이스에 "MEMBER_SEQ"라는 시퀀스를 생성 후 이용한다.

Member member = new Member();

System.out.println("====================");
em.persist(member);
System.out.println("member.id  = " + member.getId());
System.out.println("====================");
Hibernate: create sequence MEMBER_SEQ start with 1 increment by 1
====================
Hibernate:
	call next value for MEMBER_SEQ
member.id = 1
====================
Hibernate:
	/* insert hellojpa.Member
    	*/ insert
        into
        	Member
            (id, name)
        values
        	(null, ?)

IDENTITY 전략과 상당히 다른 것을 확인할 수 있다.

  1. 먼저 DB에 MEMBER_SEQ 시퀀스를 생성한다.

  2. DB에 존재하는 MEMBER_SEQ 시퀀스에서 PK를 가져온다.
    -> em.persist()가 호출될 때 객체는 PK가 존재해야한다.

    이 시점에 IDENTITY 전략은 DB에 쿼리를 날려 데이터를 추가하고 PK를 가져온다.
    하지만 SEQUENCE 전략은 DB에 있는 시퀀스에서 PK를 가져오기만 하면 된다.
    따라서 em.persist() 시점에 insert 쿼리가 나가지 않는 것이 차이점이다.

  3. tx.commit()시점에 insert 쿼리가 나가는 것을 확인할 수 있다.

하지만 이렇게 매번 시퀀스를 받기 위해 DB와 통신하는 것이 부담스러울 수 있다. 이때 allocationSize을 사용한다.

allocationSize

  • 기본값 50개를 DB에서 가져와 메모리 상에 준비해놓고 사용한다.
    여러 데이터를 이어서 persist() 하면서 next value를 call 하지 않는다.
    (남은 시퀀스 49개를 모두 사용할 때 까지는 메모리 상의 ID를 사용하는 것이다.)

만약 allocationSize를 50으로 설정했다면

Hibernate:
	call next value for MEMBER_SEQ
Hibernate:
	call next value for MEMBER_SEQ

시퀀스를 두번 호출한다. 왜 시퀀스를 두번 호출하는 것일까?

시퀀스 생성 직후 현재값 : -49, 증가 : 50으로 설정 되어있다.
이후, 시퀀스가 호출이 되면 현재값 : 1, 증가 : 50으로 설정된다.
이후, 시퀀스가 다시 한번 호출이 되면 현재값 : 51, 증가 : 50으로 설정된다.

-> 우리가 allocationSize를 50으로 설정했기 때문에, 최초에 Id값으로 1을 가져오고
크기 50만큼 데이터에 미리 불러온 후, 현재 값을 51로 설정하는 것이다.

3개의 객체를 em.persist()한다고 생각해보자.

em.persist(member1)		// DB SEQ = 1	//	이 시점에 SEQUENCE 두번 호출	// ID : 1
em.persist(member2)		// DB SEQ = 51	//	MEMORY 호출					// ID : 2
em.persist(member3)		// DB SEQ = 51	//	MEMORY 호출					// ID : 3

Table

  • 키 생성 전용 테이블을 하나 만들어서 데이터베이스 시퀀스를 흉내내는 전략

장점 : 모든 데이터베이스에 적용 가능
단점 : 테이블이 따로 생기기 때문에 락이 걸리는 등 성능이 좋지 않다.

@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;
Hibernate :

  create table MY_SEQUENCES ( 
   sequence_name varchar(255) not null, 
   next_val bigint, 
   primary key ( sequence_name ) 
  )

코드 실행 시점에 SEQUENCE테이블을 생성하는 것을 확인할 수 있다.

allocationSize

  • SEQUENCE전략과 같은 기능을 한다.

  • 메모리에 미리 값을 올려두는 방식이기 때문에, 여러 서버에서 동시 호출해도 동시성 문제가 없다.


권장하는 식별자 전략

  • 기본 키(PK) 제약 조건: null이 아니면서, 유일하고, 변하면 안된다.

  • 미래까지 이 조건을 만족하는 자연키는 찾기 어렵다. ex) 주민번호, 전화번호 ...etc
    -> 대리키를 이용하자

  • 권장: Long형 + 대체키 + 키 생성전략 사용


참고 :

김영한. 『자바 ORM 표준 JPA 프로그래밍』. 에이콘, 2015.

자바 ORM 표준 JPA 프로그래밍 - 기본편

profile
꾸준하게

0개의 댓글