JPA와 기본 키 매핑에 관하여

JPA 기본 키 매핑

기본키를 매핑하려면 @Id 어노테이션을 필드위에 선언해주면 돼!!

추가적으로 @GeneratedValue라는 어노테이션과 함께 많이 사용하는데 이 어노테이션에 대해 알아보자!!

먼저 기본 키 매핑 방법에는 두가지가 있어!

직접할당과 자동생성


직접 할당

: 별거 없어.. 그냥 @Id만 붙여서 사용하면 들어가는 value에 대해서는 프로그래머가 신경써야하는 것이 되는거야!! 말그대로 직접할당이지..


자동 생성 (@GeneratedValue)

: 여기에는 4가지 전략이 있어

  • IDENTITY : 데이터베이스에 위임, MYSQL
  • SEQUENCE : 시퀀스 오브젝트 사용, ORACLE
  • TABLE : 키 생성용 테이블 사용
  • AUTO : 방언에 따라 자동 지정 (DEFAULT)

각각에 대해 조금 더 자세히 적어보즈아


IDENTITY

: 기본 키 생성을 데이터베이스에 위임해

주로 MySQL, PostgreSQL, DB2 드엥서 사용한데.

@GeneratedValue(strategy = GenerationType.IDENTITY) 이렇게 선언해주면 돼!!

1
2
3
4
5
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
}

이렇게 말이야.

특징은 아래와 같애

  • IDENTITY 전략은 em.persist() 시점에 즉시 INSERT SQL을 실행하고 DB에서 식별자 조회를 해!!

    WHY?? 🤔🤔🤔

    DB에 INSERT 후에 ID 값을 알 수 있다고 하였는데 영속성 컨택스트의 관리대상 즉 영속상태가 되기 위해서는 ID, VAL 형태로 관리가 되어야하는데 KEY가 없으니 관리 대상이 될 수가 없는 상황인 것이야!!

    → 이에 대한 해결책으로 em.persist()가 호출되는 시점에 바로 db에 insert 쿼리를 날리고 db에서 id(pk)를 조회해서 영속성 컨텍스트에(1차캐시) 해당 값을 넣어주는거야!!

  • 그렇기에 모아서 insert하는 것은 불가능해!! (but 버퍼링해서 쿼리를 날리는게 엄청나게 이득을 보거나 하지는 않기에 크게 신경안써도 노상관)


SEQUENCE

: 데이터베이스 Sequence Object를 사용해

(Sequence Object란 유일한 값을 순서대로 생성하는 특별한 디비 오브젝트야)

특징은 아래와 같애

  • 오라클, PostgreSQL, DB2, H2에서 사용해
  • 테이블마다 Sequence Object를 따로 관리하고 싶다면 @SequenceGenerator에 sequenceName 속성을 추가해주면 돼
1
2
3
4
5
6
7
8
9
10
11
@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;
}

이런식으로 말야!!

  • 결론적으로는 generator에 매핑된 Sequence 전략에서 id 값을 얻어오는거야. insert query를 날리기전에 id 값을 알기에 지연쓰기가 가능해!!
  • allocationSize를 1로 설정할 경우 네트워크를 많이 타야 돼.(어차피 디비 시퀀스 오브젝터라는 놈한테서 사용할 id 값을 가져오는 것이기에)
  • 위의 경우에서 allocationSize를 보통 50정도로 지정함으로써 그러한 네트워크 타는 횟수를 줄일 수 있어. 50으로하면 디비상에서 한번에 50단위로 id로 사용할 value를 받고 메모리 상에서 하나씩 하나씩 사용하는 거야!! 그러다가 다 사용하게 되면 다시 Database의 시퀀스 오브젝트로부터 가져오고~ 그런 과정의 반복이지. 그럼 결과적으로 네트워크 타는 횟수를 줄일 수 있게 되는거야 (만약 무조건 크면 더 좋은 것 아니냐는 의문이 들 수 있는데 자원의 낭비 문제가 발생할 수 있어)
  • 속성
속성 설명 기본 값
name 식별자 생성기 이름 필수
sequenceName 데이터베이스에 등록되어 있는 시퀀스 이름 hibernate_sequence
initialValue DDL 생성 시에만 사용되며 시퀀스 DDL을 생성할 때 처음 1 시작하는 수를 지정 1
allocationSize 시퀀스 한 번 호출에 증가하는 수(성능 최적화에 사용됨 데이터베이스 시퀀스 값이 하나씩 증가하도록 설정되어 있으면 이 값을 반드시 1로 설정해야 한다 50
catalog,schema 데이터베이스 catalog, schema 이름

TABLE

: 키 생성 전용 테이블을 하나 만들어서 데이터베이스 시퀀스를 흉
내내는 전략이야. 거의 사용할 일이 없다기에 구체적인 내용은 생략!

추가로 권장하는 식별자 전략에 대해 잠깐 생각해보자

해답은 Long형 + 대체키 + 키 생성전략 사용 이야!!

why??

기본키 제약조건에는 null이 아니다, 유일하다, 변하면 안된다가 있따.

여기서 변하면 안된다에 조금 주목을 해볼 필요가 있다.

미래에 어떠한 일이 발생할지는 예측불가능이다. 현재 키로 사용하고 있는 column에 대해 영원히 어떤 변화가 없을 것이라는 장담은 할 수 없다. (예를들어 pk로 사용하고 있는 컬럼에 대해 “해당 컬럼 정보는 디비에서 제외시켜주세요! 법이 바뀌었어요” 이런 경우)

그렇기에 비지니스와 관계없는 대체키를 사용하는 것이 안전하다.

😐 db connection pool과 deadlock에 대해 issue가 있는데 이에 대한 부분은 까먹지 말고 따로 정리하즈아!!









https://gmlwjd9405.github.io/2019/08/12/primary-key-mapping.html

https://www.inflearn.com/course/ORM-JPA-Basic