[JPA] 엔티티 매핑
깃허브 바로가기
JPA에서 가장 중요한 것은 엔티티와 테이블 매핑을 정확히 하는 것이다.
매핑 어노테이션을 잘 숙지해야 한다.
- 객체와 테이블 매핑 :
@Entity
,@Table
- 기본 키 매핑 :
@Id
- 필드와 컬럼 매핑 :
@Column
- 연관관계 매핑 :
@ManyToOne
,@JoinColumn
@Entity
JPA를 사용해서 테이블과 매핑할 클래스는 @Entity
어노테이션을 필수로 붙여야 한다.@Entity
가 붙은 클래스는 JPA가 관리하는 것으로 엔티티라고 부른다.
속성 | 기능 | 기본값 |
---|---|---|
name | JPA에서 사용할 엔티티 이름을 정한다. 보통 기본값인 클래스 이름을 사용한다. 만약 다른 패키지에 이름이 같은 엔티티 클래스가 있다면 이름을 지정해서 충돌하지 않도록 해야 한다. | 설정하지 않으면 클래스 이름 그대로 사용 |
@Entity
적용시 주의 사항
- 기본 생성자는 필수(파라미터가 없는 public or protected 생성자)
- Lombok에서는
@NoArgsConstructor
사용
- Lombok에서는
- final 클래스, enum, interface, inner 클래스에는 사용할 수 없다.
- 저장할 필드에 final을 사용하면 안된다.
생성자가 하나도 없을 때 자바는 기본 생성자를 생성하지만, 생성자 오버로딩을 했을 때는 개발자가 직접 기본 생성자를 만들어줘야 한다.
@Table
@Table은 엔티티와 매핑할 테이블을 지정. 생략시 매핑한 엔티티 이름을 테이블 이름으로 사용
속성 | 기능 | 기본값 |
---|---|---|
name | 매핑할 테이블 이름 | 엔티티 이름을 사용 |
catalog | catalog 기능이 있는 DB에서 catalog매핑 | |
schema | schema 기능이 있는 DB에서 schema 매핑 | |
uniqueConstraints | DDL 생성시 유니크 제약조건을 만듦. 2개 이상의 복합 유니크 제약조건도 만들 수 있다. 스키마 자동생성기능을 사용해서 DDL을 만들때만 사용 |
다양한 매핑
@Enumerated
: 자바의 enum을 사용할 때@Temporal
: 자바의 날짜타입 매핑@LOB
: CLOB, BLOB 타입 매핑
DB 스키마 자동생성
JPA는 DB스키마를 자동 생성하는 기능을 지원.
application.yaml
spring:
jpa:
hibernate:
ddl-auto: create
어플리케이션 실행 시점에 DB테이블 자동으로 생성
옵션 | 설명 |
---|---|
create | 기존 테이블을 삭제하고 새로 생성, DROP + CREATE |
create-drop | create 속성에 추가로 어플리케이션을 종료할때 DDL 제거, DROP + CREATE + DROP |
update | DB 테이블과 엔티티 매핑정보를 비교해서 변경 사항만 수정 |
validate | DB 테이블과 엔티티 매핑정보를 비교해서 차이가 있으면 경로를 남기고 어플리케이션을 실행하지 않는다. 이것은 DDL을 수정하지 않음. |
none | 자동 생성 기능을 사용하지 않으려면 ddl-auto 속성을 제거하거나 유효하지 않은 옵션 값을 주면 된다.(none은 유효하지 않은 옵션값) |
sql보기
spring:
jpa:
properties:
hibernate:
show_sql: true
DDL생성 기능
@Column
매핑정보의 nullable속성 값을 false로 지정하면 자동 생성되는 DDL에 not null
제약조건을 추가할 수 있다. 자동 생성되는 DDL에 문자 크기를 length옵션으로 지정할 수 있다.
@Table
에 유니크 제약조건을 만들어주는 uniqueConstraints 속성은 유니크 제약조건을 말 그대로 걸어주는 것인데 이 속성들은 DDL을 자동 생성할때만 사용되고 JPA 실행 로직에는 영향을 주지 않는다.
직접 DDL을 만들면 사용할 이유가 없는 속성들이다.
그럼에도 이 기능을 사용한다면 엔티티만 보고도 다양한 제약조건을 파악할 수 있다는 장점이 존재
기본키 매핑
@Entity
public class Member{
@Id
@Column(name= "ID")
private String id;
JPA에서 제공하는 DB 기본키 생성 전략
- 직접 할당 : 기본 키를 어플리케이션에서 직접 할당
- 자동 생성 : 대리 키 사용 방식
- IDENTITY : 기본 키 생성을 DB에 위임
- SEQUENCE : DB시퀀스를 사용하여 기본 키 할당
- TABLE : 키 생성 테이블을 사용
자동생성 전략이 다양한 이유는 DB벤더마다 지원하는 방식이달라서 이다.
SEQUENCE나 IDENTITY 전략은 사용하는 DB에 의존
기본키를 할당하려면 @Id 사용, 자동생성 전략을 이용하려면 @GeneratedValue
를 사용하면 된다.
IDENTITY 전략
기본 키 생성을 DB에 위임하는 전략
MySQL, Postgre, SQL Server, DB2 에서 사용
@Id
@GeneratedValue(strategy = GenertaionType.IDENTITY)
private Long id;
IDENTITY는 데이터를 DB에 insert한 후에 기본 키 값을 조회할 수 있음.
그러므로 엔티티에 식별자 값을 할당하려면 추가로 DB를 조회해야함
SEQUENCE 전략
유일한 값을 순서대로 생성하는 전략
Oracle, Postgre, DB2, H2 에서 사용 가능@SequenceGenerator
에 시퀀스 생성기를 name이값에 등록하고
sequenceName 속성 이름으로 DB 시퀀스를 매핑함
그러면서@GenerateValue(strategy = Generation.Type.SEQUENCE, generator = "SequenceGenerator의 name값"
)
사용하면 시퀀스 생성기 할당됨
@SequenceGenerator
속성 | 기능 | 기본값 |
---|---|---|
name | 식별자 생성기 이름 | 필수 |
sequenceName | DB에 등록된 시퀀스 이름 | hibernate_sequence |
initialValue | DDL 생성시에 사용, 시퀀스 DDL 생성할때 처음 시작하는 수 지정 | 1 |
allocationSize | 시퀀스 한번 호출에 증가하는수(성능최적화에 사용) | 50 |
catalog, schema | 데이터베이스 catalog, schema이름 |
DDL ex - create sequence [sequenceName]
start with [initialValue] increment by [allocationSize]
TABLE 전략
키생성 전용 테이블을 하나 만들고 이름과 값으로 사용할 컬럼 만든후 시퀀스를 흉내내는 전략
create table MY_SEQUENCES {
sequence_name varchar(255) not null,
next_val bigint,
primary key (sequence_name)
}
@GeneratorValue(generator = "BOARD_SEQ_GENERATOR")
@TableGenerator
속성 | 기능 | 기본값 |
---|---|---|
name | 식별자 생성기 이름 | 필수 |
table | 키생성 테이블명 | hibernate_sequences |
pkColumnName | 시퀀스 컬럼명 | sequence_name |
valueColumnName | 시퀀스 값 컬럼명 | next_val |
pkColumnValue | 키로 사용할 값 이름 | 엔티티 이름 |
initialValue | 초기 값, 마지막으로 생성된 값이 기준 | 0 |
allocationSize | 시퀀스 한번 호출에 증가하는 수(성능 최적화) | 50 |
catalog, schema | DB catalog, schema 이름 | |
uniqueConstraints(DDL) | 유니크 제약 조건 지정 |
AUTO 전략
선택한 DB의 방언에 따라 Identity, Sequence, Table 전략중 하나 자동으로 설정
기본키 매핑 정리
영속성 컨텍스트는 엔티티를 식별자 값으로 구분하기 때문에 엔티티를 영속 상태로 만드려면 식별자 값은 반드시 포함해야 하는 사실. em.perist()
를 호출한 직후 발생하는일을 정리하면 아래와 같다.
- 직접 할당
em.persist()
를 호출하기 전에 애플리케이션에서 직접 식별자 값 할당- 없다면 예외발생
- SEQUENCE
- DB 시퀀스에서 식별자 값 획득 후 영속성 컨텍스트에 저장
- TABLE
- DB 시퀀스 생성용 테이블에서 식별자 값 획득 후 영속성 컨텍스트 저장
- IDENTITY
- DB에 엔티티를 저장한 다음 식별자 값 획득 후 영속성 컨텍스트 저장
- 테이블에 데이터를 저장해야 식별자 값 획득이 가능
레퍼런스
JPA에서 제공하는 필드와 컬럼 매핑용 어노테이션 정리
분류 | 매핑 어노테이션 | 설명 |
---|---|---|
필드와 컬럼 매핑 | ||
@Column | 컬럼을 매핑 | |
@Enumerated | 자바 enum 타입 매핑 | |
@Temporal | 날짜 타입 매핑 | |
@Lob | CLOB, BLOB 타입 매핑 | |
@Transient | 특정 필드를 DB에 매핑하지 않음 | |
기타 | @Access | JPA가 엔티티에 접근하는 방식 지정 |
@Column
속성 | 기능 | 기본값 |
---|---|---|
name | 필드와 매핑할 테이블 컬럼이름 | 객체의 필드이름 |
nullable(DDL) | null값 허용 여부 설정. false설정 시 DDL조건에 not null제약조건 추가됨 | true |
unique(DDL) | 한 컬럼에 간단히 유니크 제약조건 걸 때 사용, 두 컬럼 이상 사용시 @Table.uniqueConstraints사용 | |
ColumnDefinition(DDL) | DB 칼럼 정보 직접 줄 수 있음 | 필드의 자바 타입과 방언 정보를 사용해서 적절한 컬럼 타입 생성 |
length(DDL) | 문자 길이 제약조건, String타입에만 사용 | 255 |
precision, scale(DDL) | BigDecimal타입에서 사용 precision은 소수점 포함 전체자리수, scale은 소수 자리수, float이나 double타입에는 적용 안됨 | precision = 19, scale= 2 |
안쓰는 것은 구글링을 해서 찾아야겠다.
@Enumerated
- EnumType.ORDINAL은 enum정의된 순서대로 0, 1 순서로 DB에 저장
- 장점 : DB에 저장되는 데이터 크기가 작음
- 단점 : 이미 저장된 enum의 순서를 변경할 수 없음
- EnumType.STRING은 enum 이름 그대로 DB에 저장
- 장점 : 저장된 enum의 순서가 바뀌거나 enum이 추가되어도 안전
- 단점 : DB에 저장되는 데이터 크기가 ORDINAL에 비해 큼
@Temporal
TemporalType필수 지정
- value
- TemporalType.DATE: 날짜, DB date 타입 매핑
- TemporalType.TIME: 시간, DB time 타입 매핑
- TemporalType.TIMESTAMP: 날짜와 시간, DB timestamp 타입과 매핑
@Lob
지정할 수 있는 속성이 없음.
대신 매핑하는 필드타입이 문자라면 CLOB으로 매핑 나머지는 BLOB으로 매핑
@Transient
매핑하지 않는 필드, 그렇기 때문에 DB에 저장하지도 않고 조회하지도 않음.
객체에 임시로 어떤 값을 보관하고 싶을 때 사용함.
@Access
엔티티 데이터에 접근하는 방식 지정
- 필드 접근 :
AccessType.FILED
로 지정.- 필드에 직접 접근, 접근 권한이 private여도 접근 가능
- 프로퍼티 접근 :
AccessType.PROPERTY
로 지정. 접근자(Getter) 사용.
@Access
를 설정하지 않으면 @Id
위치를 기준으로 접근방식 설정
@Id
가 필드에 있으면 @Access(AccessType.FILED)
로 설정한 것과 같음.
그래서 생략 가능