기본 키 매핑

직접 할당

  • @Id만 사용하는 방식

자동 생성

  • @GeneratedValue를 추가한 방식

IDENTITY

  • 기본 키 생성을 데이터베이스에 위임한다.

    • ex. MySQL의 AUTO_INCREMENT

    • 주로 MySQL, PostgreSQL, SQL Server, DB2에서 사용한다.

  • 데이터베이스에 insert SQL을 실행해야 ID 값을 알 수 있다.

  • IDENTITY 전략의 Id 값은 DB에 insert 쿼리로 데이터가 실제 들어가야 알 수 있다.

  • 그런데 영속성 컨텍스트에서 관리되려면 PK 값이 필요하다.

    • 그림처럼 1차 캐시의 Id 값에 PK가 들어가야 한다.

  • 그래서 JPA는 identity 전략에서만 em.persist()로 호출하자 마자 바로 insert 쿼리를 날려버린다.

코드를 실행해보면 persist()시에 insert 쿼리가 나가고 id를 조회할 수 있는 걸 확인할 수 있다.

  • 조회할 때는 select 쿼리를 미리 치지 않는다.

    • JDBC 드라이버에 insert 쿼리 직후 바로 리턴 받을 수 있는 기능이 있기 때문이다.

  • 전략을 sequence나 따로 지정할 수 있는 방법으로 바꾸면 commit 시점에 쿼리가 날아간다.

SEQUENCE

  • Integer는 범위가 부족할 수 있어 Long 타입을 사용한다.

  • 데이터베이스에 시퀀스 오브젝트를 만들어서 이 값을 통해 세팅한다.

  • 오라클, PostgreSQL, DB2, H2에서 사용한다.

  • persist() 할 때는 무조건 PK가 존재해야 한다.

  • JPA는 전략이 sequence면 id 값을 DB에서 먼저 가져온다.

    • 이와 동시에 다음 시퀀스 값으로 넘어간다.

    • 그래서 persist() 시점에 id를 조회할 수 있는 것이다.

    • 아직 insert 쿼리가 나아간 것은 아니다.

  • 그 상태로 영속성 컨텍스트에 남아있다가 실제 커밋하는 시점에 insert 쿼리가 호출된다.

IDENTITY는 무조건 insert를 날려야 했는데 SEQUENCE는 시퀀스 값만 낼름 가져온다.

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

  • allocationSize

    • 기본값 50개를 DB에서 가져와 메모리 상에 일단 준비해놓고 거기서 사용한다.

      • 여러 데이터를 이어서 persist() 하면서 next value를 call 하지 않는다.

    • 다 쓰면 다시 call 해서 그 다음 50개를 가져온다.

    • 여러 웹 서버가 있어도 동시성 문제 없이 다양한 이슈가 해결된다.

실제 시퀀스 값을 보면 실행 전에는 현재 값이 -49로 세팅되어있다.

데이터가 추가되면 1이 된다.

로그를 보면 시퀀스를 두 번 호출했다. DB 상 시퀀스가 가지고 있는 id가 맨 처음엔 1이었다가 두번째에 51에 된 것이다.

애플리케이션 상에서는 member 3개를 저장해야 하니까 id가 하나 이상이 필요하므로 51까지 만들어둔 시퀀스에서 차례로 2, 3을 갖게 된다.

  • 처음에 dummy로 호출해서 1이 된 뒤에 next call이 51이 되도록 해서 50개를 확보한다.

  • 그 안에서 더 이상 call을 하지 않고도 id를 추가하고 있는 걸 볼 수 있다.

  • 이후 51을 만나는 순간 call을 한 번 더 하게 될 것이다.

Table

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

  • 장점

    • 모든 데이터베이스에 적용할 수 있다.

  • 단점

    • 테이블이 따로 생기다보니 락이 걸리는 등 성능이 좋지 않다.

시퀀스를 만드는 MY_SEQUENCE 테이블이 생성된다.

  • MEMBER 테이블에 시퀀스 테이블의 값이 ID로 들어가있다.

  • allocationSize

    • 위의 내용과 같은 기능을 한다.

    • 미리 값을 올려두는 식이기 때문에 서버 여러 대가 동시에 호출해도 자기가 쓸 값 범위만 값이 쭉 올라가 있어 동시성 문제가 없다.

권장하는 식별자 전략

  • 기본 키 제약 조건

    • null 아니면서

    • 유일하고

    • 변하면 안된다

  • 변하면 안된다는 조건이 미래까지 지켜질만한 자연키(주민번호, 전화번호 등 비즈니스적으로 의미있는 키)를 찾기 힘들다.

  • 예제에서 살펴본 것과 같은 대리키(대체키)를 사용하자.

    • Long 타입

    • 대체키(시퀀스, UUID 등)

    • 키 생성 전략 조합

Last updated