오늘의하루

JPA 기본키 매핑 본문

Spring/JPA

JPA 기본키 매핑

오늘의하루_master 2024. 1. 12. 17:20

JPA에서 기본키를 매핑하는 방법은 @Id, @GeneratedValue 이렇게 두가지가 있다.

@Id의 경우 직접 할당 하겠다는 의미이기 때문에 별다른 내용이 없다.

 

매핑 방법

@GeneratedValue는 자동 생성을 해주는 것이다.

  • SEQUENCE : DB의 시퀀스 사용
    • ORACLE의 경우 @SequenceGenerator가 필요하다.
  • IDENTITY : DB에 위임
  • TABLE : 키 생성용 테이블을 만들어서 사용한다.
    • @TableGenerator가 필요하다.
    • 장점으로는 모든 DB에서 공통적으로 사용가능하다.
    • 단점은 테이블이 생겨나기 때문에 추후 성능에 좋지 않다.
  • AUTO : Hibernate에서 지정한 방언에 따라 자동으로 지정된다. (기본값)

IDENTITY 전략 - 매핑

이 전략은 기본 키 생성 자체를 DB에 위임하는 것이다.

보통 JPA는 commit 또는 flush 시점에서 쿼리가 날아간다.

이때 기억해야 하는 영속성 컨텍스트가 쓰기 지연 SQL 저장소에 쿼리를 쌓을때는 꼭 1차 캐시에 저장 한 후 진행된다.

그리고 1차 캐시는 key와 value가 쌍으로 이루어진 구조이며 1차 캐시의 key는 기본키가 들어간다는 것이다.

그럼 IDENTITY는 DB에 위임을 한다고 했는데 어떻게 쿼리를 날리는 것일까?

IDENTITY 전략을 할 경우 JPA에서는 객체를 영속성 컨텍스트에 넣는 em.persist() 시점에서 Insert 쿼리를 날린다.

그리고 여기서 또 한가지 알게된 점은 JPA에서 DB에 쿼리를 날리면 기본적으로 해당 값을 조회하여 그 결과를 객체에 저장해준다는 것이다.

tx.begin();
try{
    Member member = new Member();
    member.setName("test");
    
    System.out.println("========");
    em.persist(member);
    System.out.println("member.id = " + member.getId());
    // commit 되는 시점이 아닌 영속성 컨텍스트에서 관리하도록 하는 시점에서 쿼리가 날아간다.
    // 그 후 Member객체를 확인하면 Id값을 알 수 있다.
    // 이 말은 그 전엔 현재 Id값을 알 수 없다는 말이다.
    System.out.println("========");
    
    tx.commit();
}catch(Exception e){
    tx.rollback();
}finally{
    em.colse();
}

SEQUENCE 전략 - 매핑

DB의 시퀀스는 유일한 값을 사용자가 지정한 규칙적인 순서대로 생성되는 DB의 특별한 오브젝트이다.

주로 ORACLE, PostgreSQL, DB2, H2에서 사용하고 있다.

SEQUENCE 전략은 em.persist() 시점에서 DB에 select 쿼리를 날려서 현재와야할 시퀀스 값을 조회한 후 영속성 컨텍스트의 1차 캐시에 저장하며 동시에 쓰기 지연 SQL 저장소에 쌓아두게 된다.

그 후 commit 또는 flush 시점에서 DB에 쿼리를 날리게된다.

@Entity
@SequenceGenerator(
    name = "MEMBER_SEQ_GENERATOR",
    sequenceName = "MEMBER_SEQ", // 매핑 하게 될 DB의 시퀀스 이름을 지정해준다.
    // 만약 이름을 지정하지 않으면 hibernate에서 지정한 기본적인 이름이 들어간다.
    initalValue = 1,
    allocationSize = 1 // allocationSize의 기본값은 50이다.
)
public class Member{
    @Id
    @GeneratedValue(
        strategy = GenerationType.SEQUENCE,
        generator = "MEMBER_SEQ_GENERATOR"
    )
    private Long id;
    
    private String name;
}
  • name : 각각의 객체마다 실별할 수 있는 이름 값이다. (필수)
  • sequenceName : DB에 등록되어 있는 시퀀스 이름
    • 지정하지 않을 경우 기본적으로 "hibernate_sequence"가 들어간다.
  • initalValue : DDL 생성 시에만 사용되며 시퀀스 DDL을 생성할 때 처음 시작하는 수를 지정한다.
  • allocationSize : 시퀀스를 한 번 호출에 증가하는 수이며 성능 최적화에 사용된다.
    • 이 뜻은 지정한 값만큼 확보해두고 확보 한것을 할당하는 것이다.
      • 주로 50 또는 100정도로 지정해서 사용하고 있다.
    • DB 시퀀스 값이 하나씩 증가하도록 설정되어 있ㄴ으면 이값을 반드시 1로 설정해야 한다.
tx.begin();
try{
    Member member1 = new Member();
    member1.setName("A");
    Member member2 = new Member();
    member2.setName("B");
    Member member3 = new Member();
    member3.setName("C");
    
    System.out.println("=============");
    em.persist(member1);
    em.persist(member2);
    em.persist(member3);
    System.out.println("=============");
    
    tx.begin();
}catch(Exception e){
    tx.rollback();
}finally{
    em.colse();
}

권장하는 식별자 전략

DB의 식별자는 null이 아니여야 하고 유일해야 하며 변하면 안된다.

'Spring > JPA' 카테고리의 다른 글

[JPA] LazyInitializationException 발생!  (0) 2024.02.14
JPA 연관 관계 매핑 - start  (1) 2024.01.14
JPA 엔티티 매핑  (0) 2024.01.02
JPA에서 batch_size를 지정하는 이유는?  (0) 2024.01.02
JPA의 영속성 관리  (0) 2023.12.31
Comments