티스토리 뷰
이전 글: https://gojs.tistory.com/44
JPA 영속성 관리
영속성 컨텍스트란?영속성 컨텍스트란 엔티티를 영구 저장하는 환경이다.EntityManager로 엔티티를 저장하거나 조회하면 영속성 컨텍스트에 저장되고 조회된다. em.persist(member);이러한 코드를 실행
gojs.tistory.com
@Entity
엔티티 클래스에 필수로 붙어야하는 어노테이션이다.
속성 | 설명 | 기본값 |
name | 엔티티 이름을 설정한다. 보통 클래스 이름을 그대로 사용한다. | 클래스 이름 |
엔티티 클래스는 아래와 같은 제약조건을 가지고 있다.
- 기본 생성자가 꼭 필요하다.
- 파라미터가 없는 public/protected 생성자
- final, enum, interface, inner 클래스여서는 안된다.
- 저장할 필드가 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가 할당하게 되며 아래와 같이 동작한다.
- 시퀀스로 식별자 조회
- 조회된 식별자를 엔티티에 할당
- 엔티티를 영속 상태로 변경
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 |