티스토리 뷰

공부/JPA

JPA Entity 구성하기

JStack 2024. 7. 24. 23:29

이전 글: https://gojs.tistory.com/44

 

JPA 영속성 관리

영속성 컨텍스트란?영속성 컨텍스트란 엔티티를 영구 저장하는 환경이다.EntityManager로 엔티티를 저장하거나 조회하면 영속성 컨텍스트에 저장되고 조회된다. em.persist(member);이러한 코드를 실행

gojs.tistory.com

 

@Entity

엔티티 클래스에 필수로 붙어야하는 어노테이션이다.

속성 설명 기본값
name 엔티티 이름을 설정한다. 보통 클래스 이름을 그대로 사용한다. 클래스 이름

엔티티 클래스는 아래와 같은 제약조건을 가지고 있다.

  1. 기본 생성자가 꼭 필요하다.
    • 파라미터가 없는 public/protected 생성자
  2. final, enum, interface, inner 클래스여서는 안된다.
  3. 저장할 필드가 final 필드이면 안된다.

 

@Table

엔티티와 매핑할 테이블을 지정하는 어노테이션이다.

속성 설명 기본값
name 매핑할 테이블 이름 엔티티 이름
catalog catalog 기능이 있는 데이터베이스에서 catalog를 매핑  
schema schema 기능이 있는 데이터베이스에서 schema를 매핑  
uniqueConstraints DDL 자동 생성 시 유니크 제약조건을 함께 생성  

 

기본 엔티티 매핑 예제

import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;

import java.util.Date;

@Entity
@Table(name = "MEMBER")
@Getter
@Setter
public class Member {

    @Id
    @Column(name = "ID")
    private String id;

    @Column(name = "NAME")
    private String username;

    // mapping 정보가 없는 field
    private Integer age;

    @Enumerated(EnumType.STRING)
    private RoleType roleType;

    @Temporal(TemporalType.TIMESTAMP)
    private Date createDate;

    @Temporal(TemporalType.TIMESTAMP)
    private Date lastModifiedDate;

    @Lob
    private String description;
}
public enum RoleType {
    ADMIN, USER
}

위와 같이 몇 개의 필드를 추가하여 현재 H2 데이터베이스의 테이블 정보와 다른 정보를 가진 엔티티로 수정한다.

 

jpa:
    hibernate:
    ddl-auto: create

그리고 위와 같은 설정값을 추가하면 애플리케이션 실행 시점에 데이터베이스 테이블을 자동으로 생성한다.

 

H2 데이터베이스에 생성할 때 데이터베이스 방언에 따라 role_type 컬럼의 타입은 varchar, create_date 컬럼은 timestamp(6), descriptions 컬럼은 clob 타입으로 생성되었다.

해당 기능은 테이블이 존재하면 drop 쿼리가 먼저 나가버리기 때문에 운영환경에서 사용하면 안된다.

운영환경에서는 더 낮은 레벨의 ddl-auto 설정을 하거나 아예 사용하지 말아야 한다.

ddl-auto 속성
  - create : 기존 테이블 삭제 후 생성
  - create-drop : 기존 테이블 삭제 후 생성, 애플리케이션 종료할 때 삭제
  - update : 테이블과 엔티티 정보를 비교해서 변경 사항만 수정
  - validate : 테이블과 엔티티 정보가 차이가 있으면 애플리케이션 실행하지 않음

 

테이블 명세 핸들링

    ...
    @Column(name = "NAME", nullable = false, length = 10)
    private String username;

컬럼 어노테이션의 속성을 활용해 컬럼 명세를 바꿀 수 있다. 위와 같이 코드를 작성하고 ddl-auto 기능을 이용하면 아래와 같은 결과를 볼 수 있다.

실행 쿼리

name 컬럼에 varchar(10) not null로 명세가 바뀌었다.

 

@Table(name = "MEMBER", uniqueConstraints = {@UniqueConstraint(
        name = "NAME_AGE_UNIQUE",
        columnNames = {"name", "age"}
)})

그리고 위와 같이 테이블 어노테이션에 속성을 추가하여 유니크 키 제약조건을 추가할 수 있다.

ddl-auto 기능을 이용하니 이와 같이 유니크 키가 같이 생성되었다.

테이블 명세 핸들링은 ddl-auto를 사용하는 경우에만 유효하지만, ddl-auto를 사용하지 않더라도 개발자가 엔티티만 보더라도 제약조건이나 명세를 확인할 수 있다는 장점이 있다.

 

기본 키 매핑

JPA에서 기본 키를 할당하기 위해서 제공하는 전략은 아래와 같다.

  • 직접 할당: 기본 키를 애플리케이션에서 직접 할당
  • 자동 생성: 대리 키 사용 방식
    • IDENTITY: 기본 키 생성 방식을 데이터베이스에 위임
    • SEQUENCE: 데이터베이스 시퀀스 사용
    • TABLE: 키 생성 테이블 사용
@Id
@Column(name = "id);
private String id;

@Id 어노테이션을 사용하여 기본 키를 매핑할 수 있다.

 

직접 할당 전략

em.persist() 호출 전 엔티티의 id에 직접 값을 할당하는 전략이다.

 

IDENTITY 전략

기본 키 생성을 데이터베이스에 위임하는 전략이다.

일반적으로 MySQL, PostgreSQL, SQL Server, DB2에서 사용된다.

CREATE TABLE BOARD (
    ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    DATA VARCHAR(255)
);

위와 같이 테이블을 생성하고 값을 insert 하면 auto_increment 속성으로 인해서 데이터베이스가 id 값을 순서대로 채워준다.

 

이처럼 데이터베이스가 값을 채워넣어주고 나서야 기본 키 값을 구할 수 있는 경우에 IDENTITY 전략을 사용한다.

아래와 같이 @GeneratedValue 어노테이션을 사용하면 IDENTITY 전략을 사용할 수 있다.

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
IDENTITY 전략 최적화

IDENTITY 전략은 insert 이후에 select를 실행해서 기본 키를 받아와야 해서 쿼리가 두 번 발생한다.
그러나 JDBC3의 Statement.getGeneratedKeys()를 사용하여 데이터를 저장하면서 기본 키 값을 한 번에 얻어올 수 있다.

 

SEQUENCE 전략

시퀀스는 유일한 값을 순서대로 생성하는 데이터베이스 오브젝트이다.

SEQUENCE 전략은 이 시퀀스를 이용하여 기본 키를 생성하는 전략이다.

일반적으로 Oracle, PostgreSQL, DB2, H2에서 사용된다.

 

CREATE TABLE BOARD (
    ID INT NOT NULL PRIMARY KEY,
    DATA VARCHAR(255)
);

CREATE SEQUENCE BOARD_SEQ START WITH 1 INCREMENT BY 1;
@Entity
public class Board {
    @Id
    @GeneratedValue(
        strategy = GenerationType.SEQUENCE, 
        generator = "BOARD_SEQ_GENERATOR")
    @SequenceGenerator(
        name = "BOARD_SEQ_GENERATOR",
        sequenceName = "BOARD_SEQ",
        initialValue = 1, allocationSize = 1)
    private Long id;
    ...
}

위와 같이 시퀀스 오브젝트를 생성해주고 엔티티 클래스에 매핑과 관련된 정보를 입력해준다.

@GenerationValue 어노테이션에 generator 속성을 입력하고 generator 속성의 값을 @SequenceGenerator에 시퀀스 정보와 함께 입력해준다.

이렇게 되면 id 식별자 값은 sequence generator가 할당하게 되며 아래와 같이 동작한다.

  1. 시퀀스로 식별자 조회
  2. 조회된 식별자를 엔티티에 할당
  3. 엔티티를 영속 상태로 변경
SEQUENCE 전략 최적화

SequenceGenerator의 기본 설정 값은 allocationSize = 50 이다.
즉, 한번 시퀀스를 할당받을 때 50개씩 할당받는다는 의미이다.

그 이유는 성능 최적화 때문인데 SEQUENCE 전략은 데이터를 저장하면서 쿼리가 두 번 발생하게 되기 때문이다.

SELECT BOART_SEQ.NEXTVAL FROM DUAL;
INSERT INTO BOARD


따라서 시퀀스를 조회하는 쿼리를 한 번 실행 시킨 후 50번의 insert 쿼리에 대해서는 메모리에서 식별자를 할당하는 방식으로 성능 최적화를 구현한다.
만약 시퀀스 값이 한번에 많이 증가하는 것이 부담스럽거나 성능이 중요하지 않으면 allocationSize를 1로 세팅하면 된다.

 

TABLE 전략

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

CREATE TABLE MY_SEQUENCES (
    sequence_name varchar(255) not null,
    next_val bigint,
    primary key (sequence_name)
)
@Entity
public class Board {
    @Id
    @GeneratedValue(
        strategy = GenerationType.TABLE,
        generator = "BOARD_SEQ_GENERATOR")
    @TableGenerator (
        name = "BOARD_SEQ_GENERATOR",
        table = "MY_SEQUENCES",
        pkColumnValue = "BOARD_SEQ",
        allocationSize = 1)
    private Long id;
}

위와 같이 TABLE 전략을 구현할 수 있다.

@GeneratedValue의 strategy 속성을 GenerationType.TABLE로 지정하고 generator 속성에 TableGenerator 이름을 입력한다.

그리고 @TableGenerator의 table 속성에 MY_SEQUENCES 테이블을 기본 키 할당용 테이블로 이용한다.

MY_SEQUENCES 테이블의 sequence_name은 “BOARD_SEQ” 값이 입력될 것이고 next_val은 1씩 증가할 것 이다.

TABLE 전략의 최적화 방법은 SEQUENCE 전략과 같이 allocationSize를 활용하여 데이터베이스 통신을 줄이는 방식이다.

 

AUTO 전략

데이터베이스 방언에 따라 IDENTITY, SEQUENCE, TABLE 전략 중 하나를 자동으로 선택하는 전략이다.

데이터베이스가 바뀌는 경우에도 코드의 변경이 없다는 장점이 있다.

 

식별자 선택 전략

식별자 선택 전략은 크게 두 가지로 분류할 수 있다.

  • 자연키
    • 비즈니스 의미를 내포한 키
    • 주민등록번호, 이메일, 전화번호 등
  • 대리키
    • 임의로 만들어진 키
    • 대체 키
    • 시퀀스, auto_increment 등

자연키는 비즈니스 의미를 내포하기 때문에 변경의 우려가 있다. (기본적으로 비즈니스는 계속 변화한다)

기본 키를 바꾸는 것은 굉장히 큰 비용이 발생하기 때문에 이를 방지하기 위해서라도 대리키를 권장한다.

 

다음 글: https://gojs.tistory.com/46

 

JPA 연관관계 매핑 (1)

관계형 데이터베이스의 테이블간의 관계를 객체간의 연관관계로 표현할 수 있다.크게 단방향 연관관계과 양방향 연관관계로 구분할 수 있으며 이에 대해 알아보자. 단방향 연관관계회원과 팀

gojs.tistory.com

'공부 > JPA' 카테고리의 다른 글

JPA 프록시와 로딩 전략  (0) 2024.07.27
JPA Entity 간 연관관계 매핑 (2)  (0) 2024.07.27
JPA Entity 간 연관관계 매핑 (1)  (0) 2024.07.26
JPA 영속성 관리 기법  (0) 2024.07.23
JPA 기본 구성 및 알아보기  (0) 2024.07.23
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2025/08   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
글 보관함