JPA

[JPA] 기본 키 매핑 어노테이션 @Id / @GeneratedValue [IDENTITY, SEQUENCE, TABLE, AUTO]

솔솔 2021. 7. 6. 14:30
반응형

@Id

 - 내가 직접 셋팅해주는 직접 할당

 

@GeneratedValue

 - IDENTITY : 데이터베이스에 위임, MYSQL

@Id	//pk가 무엇인지 알려줌
@GeneratedValue(strategy=GenerationType.IDENTITY)
private String id;

  -> MYSQL의 autoincrement와 같이 DB가 알아서 값을 넣어주는 자동 생성 방법

Member member = new Member();
//member.setId("ID_A");
member.setUsername("Hi");
em.persist(member);

id 값은 자동할당하기로 하였기 때문에 값을 안주고 실행하게되면 MySQL 방언에 따라 아래와 같이 auto_increment로 생성된다.

순차적으로 id 값이 증가하는 것을 볼 수 있다.

 -> 생각해보면 JPA는 PK 값을 알아야 관리할 수 있다.. 캐시에도 저장되어있지않고, DB에서 조회해올 것도 없기때문에 그럼 어떻게 PK를 자동 생성해줄 수 있는걸까?

  ---> JPA는 보통 트랜잭션 커밋 시점에 SQL을 실행하지만 IDENTITY만 예외적으로 persist 호출 시점에서 insert가 발생한다. 그리고 그 pk값을 캐시에 저장해준다.

Member member = new Member();
//member.setId("ID_A");
member.setUsername("Hello");

System.out.println("=============");
em.persist(member);
System.out.println("=============member.getId : " + member.getId());
System.out.println("=============");

=> IDENTITY는 persist 호출 시점에 쿼리가 날아가기 때문에 한번에 쿼리를 날리는 작업은 불가능하다.

 

 

 - SEQUENCE : 데이터베이스 시퀀스 오브젝트 사용, ORACLE / @SequenceGenerator 필요

@Id	//pk가 무엇인지 알려줌
@GeneratedValue(strategy=GenerationType.SEQUENCE)
private Long id;

실행하게되면 시퀀스가 생성되는 것을 볼 수 있다. -> 1부터 시작하고 1씩 증가시키는 시퀀스

Member member = new Member();
//member.setId("ID_A");
member.setUsername("Hello");
em.persist(member);

실행하게되면 순차적으로 ID값이 증가하는 것을 확인할 수 있다.

** 위는 하이버네이트에서 기본으로 시퀀스를 생성해주었지만 테이블 마다 시퀀스를 따로 관리하고싶을 경우

 @SequenceGenerator를 사용하여 시퀀스를 생성해도 된다.

@Entity	//JPA가 처음 로딩될 때 사용되는 애구나 인식하기 때문에 필수로 작성
@SequenceGenerator(
		name = "MEMBER_SEQ_GENERATOR",
		sequenceName = "MEMBER_SEQ",	//매핑할 DB 시퀀스 이름
		initialValue = 1, allocationSize = 1)
public class Member { 
	
	@Id	//pk가 무엇인지 알려줌
	@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="MEMBER_SEQ_GENERATOR")
	private Long id;
    
    ...
}

원하는 시퀀스를 생성할 수 있다.

 

@SequenceGenerator 속성

 - name : 식별자 생성기 이름 / 필수

 - sequenceName : DB에 등록되어있는 시퀀스 이름

 - initialValue : DDL 생성 시에만 사용됨, 시퀀스 DDL을 생성할 때 처음 시작하는 수를 지정한다. / 기본값 : 1

 - allocationSize : 시퀀스 한 번 호출에 증가하는 수 (성능 최적화에 사용) 데이터베이스 시퀀스 값이 하나씩 증가하도록 설정되어 있으면 이 값을 반드시 1로 설정해야한다. / 기본값 : 50

더보기

allocationSize 를 기본값 50으로 할 경우.. 시퀀스를 next call 할때마다 호출하면 성능 상 문제가 될 수 있다..

next call 할 때 미리 50개를 땡겨 놓고 메모리에서 1씩 증가해서 사용하는 것!

DB에 미리 올려두고 메모리에서 사용하는 것으로 이런 방식은 여러 Web서버가 있어서 동시성 문제 없이 정상적으로 실행된다.

call next 를 두번 호출한다. 이유는 처음 호출할 땐 1이 호출되기때문에 한번 더 호출하여 51로 미리 DB에 올려놓는다. 

Member member1 = new Member();
member1.setUsername("Hello");

Member member2 = new Member();
member2.setUsername("Hello");

Member member3 = new Member();
member3.setUsername("Hello");

System.out.println("=============");
em.persist(member1);	// 시퀀스 호출 1, 51
em.persist(member2);	// 메모리에서 호출
em.persist(member3);	// 메모리에서 호출
			
System.out.println("member.getId : " + member1.getId());
System.out.println("member.getId : " + member2.getId());
System.out.println("member.getId : " + member3.getId());
System.out.println("=============");

 - catalog, schema : 데이터베이스 catalog, schema 이름

 

호출되는 시점

 - persist 호출될 때 GenerationType.SEQUENCE인 경우 쿼리를 날려 sequence를 가져와 캐시에 저장해준다. insert 쿼리는 트랜잭션 commit 시점에 날려준다.

 

 - TABLE : 키 생성용 테이블 사용, 모든 DB에서 사용 / @TableGenerator 필요

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

 장점 : 모든 데이터베이스에 적용 가능

 단점 : 테이블을 사용하는거라 Lock이 걸릴 수도 있고, 최적화가 안되어있기 때문에 성능에 문제가 있다.

 

@TableGenerator를 사용하여 테이블 생성

@Entity	//JPA가 처음 로딩될 때 사용되는 애구나 인식하기 때문에 필수로 작성
@TableGenerator(
		name = "MEMBER_SEQ_GENERATOR",
		table = "MY_SEQUENCES",
		pkColumnValue = "MEMBER_SEQ", allocationSize = 1)
public class Member { 
	
	@Id	//pk가 무엇인지 알려줌
	@GeneratedValue(strategy=GenerationType.TABLE, generator="MEMBER_SEQ_GENERATOR")
	private Long id;
      
    ....
 }

실행하면 테이블을 생성해준다.

DB를 확인해보면 테이블이 생겼고 조회해보면 값을 확인할 수 있다.

운영에서는 Table 전략을 사용하기엔 부담이 있기에 사용을 추천하지는 않는다.

@TableGenerator 속성

 - name : 식별자 생성기 이름 / 필수

 - table : 키생성 테이블명 / MY_SEQUENCES

 - pkColumnName : 시퀀스 컬럼명

 - valueColumnNa : 시퀀스 값 컬럼명 / NEXT_VAL

 - pkColumnValue : 키로 사용할 값 이름 / 엔티티 이름 / MEMBER_SEQ

 - initialValue : 초기 값. 마지막으로 생성된 값이 기준 / 기본값 : 0

 - allocationSize : 시퀀스 한 번 호출에 증가하는 수 (성능 최적화에 사용) / 기본값 : 50

 - catalog, schema : 데이터베이스 catalog, schema 이름

 - uniqueConstraints (DDL) : 유니크 제약 조건을 지정할 수 있다.

 

 - AUTO : 방언에 따라 자동 지정, 기본값

 

* 권장하는 식별자 전략

 - 기본키 제약 조건 : null이 아님, 유일해야함, 변하면 안된다.

 - 미래까지 이 조건을 만족하는 자연키(ex: 주민등록번호)는 찾기 어렵다. 대리키(대체키)를 사용하자.

 - 예를 들어 주민등록번호도 기본 키로 적절하지 않다.. pk를 주민번호로 사용하게되면 조인을 걸게되면 주민번호가 독버섯 처럼 퍼져있다..

 - 권장 : Long형 + 대체키(ex: UUID) + 키 생성전략 사용

 

 

 

인강으로 공부하면서 작성하는 글로 잘못된 정보가 있을 수도 있습니다! 잘못된 정보가 있을 시 댓글달아주세요 : 0

반응형