@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
'JPA' 카테고리의 다른 글
[JPA] @Temporal / @Lob / @Transient 속성 (0) | 2021.07.05 |
---|---|
[JPA] @Column / @Enumerated 속성 (0) | 2021.07.02 |
[JPA] @Entity / @Table 매핑 어노테이션 정리 (0) | 2021.07.01 |
[JPA] 플러시 flush란? (0) | 2021.06.30 |
[JPA] 영속성 컨텍스트 PersistenceContext (4) | 2021.06.29 |