엔티티 매핑


엔티티 매핑


엔티티 매핑 소개

설명어노테이션
객체와 테이블 매핑@Entity, @Table
필드와 컬럼 매핑@Column
기본 키 매핑@Id
연관관계 매핑@ManyToOne, @JoinColumn


객체와 테이블 매핑


@Entity

@Entity가 붙은 클래스는 JPA가 관리하는 엔티티라고 한다.

• JPA를 사용해서 테이블과 매핑할 클래스는 @Entity 필수

기본 생성자 필수(파라미터가 없는 pulic 또는 protected 생성자)

• final 클래스, enum, interface, inner 클래스 사용 ❌

• 저장할 필드에 final 사용 ❌


@Entity 속성 정리

name

@Entity(name="test")
public class Test() {...}


@Table

@Entity
@Table(name = "TB_MEMBER")
public class Member {...}

엔티티와 매핑할 DB 테이블 지정

속성기능기본값
name매핑할 테이블 이름엔티티 이름을 사용
catalog데이터베이스 catalog 매핑 
schema데이터베이스 schema 매핑 
uiqueConstraintsDDL 생성시에 유니크 제약 조건 생성 


데이터베이스 스키마 자동 생성


특징

• 애플리케이션 실행 시점에 자동으로 DDL을 생성

• 테이블 중심에서 객체 중심으로 개발 가능

데이터베이스 방언을 활용해서 데이터베이스에 맞는 적절한 DDL 생성


여기서 자동으로 생성된 DDL은 개발단(Ex. localhost)에서만 사용해야 한다.(운영서버에서는 Nope!)

만약 사용하고 싶다면 꼼꼼히 다듬은 후에 사용해야 한다.


DDL 생성기능

DDL 생성 기능은 DDL을 자동 생성할 때만 사용되고, JPA의 실행 로직에는 영향을 주지 않는다.

// 제약조건 추가: 회원 이름은 필수, 10자 초과X
@Column(nullable = false, length = 10)
private String userName;

// 유니크 제약 조건 추가
@Table(uniqueConstraints = {
    @UniqueConstraint(name="NAME_AGE_UNIQUE", columnNames = {"NAME" : "AGE"})
})


속성

<property name="hibernate.hbm2ddl.auto" value="create"/>
옵션설명
create기존테이블 삭제 후 다시 생성 (DROP + CREATE)
create-dropcreate와 같으나 종료시점에 테이블 DROP
update변경분만 반영 => 운영DB에는 사용하면 안됨
validate엔티티와 테이블이 정상 매핑되었는지만 확인
none사용하지 않음


주의사항

스크립트 짜서 해라!!

운영장비에는 절대!!! create, create-drop, update 사용하면 안된다.

CaseOption
개발 초기 단계create / update
테스트 서버update / validate (가급적이면 둘다 쓰지 않기)
스테이징과 운영서버validate / none


필드와 컬럼 매핑


예제

// pk
@Id
private Long id;

// 컬럼명
@Column(name = "name")
private String name;

private Integer age;

// enum 타입 매핑
@Enumerated(EnumType.STRING)
private RoleType roleType;

// 날짜 타입 매핑
@Temporal(TemporalType.TIMESTAMP)
private Date createdDate;

// 큰 데이터를 넣고 싶을 때
// @Lob + String = C-LOB
@Lob
private String description;

// 특정 필드를 컬럼에 매핑하지 않음 => 메모리에서만 쓸 때
@Transient
private String temp;


@Column

unique = true 의 경우에는 자동으로 생성되는 이름을 해석하기 힘들다.

따라서 class 레벨에서 @Table을 지정해서 사용하는게 좋다.


@Enumerated (ORDINAL 사용금지)

옵션설명
ORDINALenum 순서를 데이터베이스에 저장
STRINGenum 이름을 데이터베이스에 저장


@Temporal

참고 : LocalDate, LocalDateTime을 사용할 때는 생략 가능

날짜 타입(Date, Calendar)을 매핑할 때 사용.


@Lob

• 데이터베이스 BLOB, CLOB 타입과 매핑

• @Lob에는 지정할 수 있는 속성이 없다.

• 매핑하는 필드 타입이 문자면 CLOB, 나머지는 BLOB


기본 키 매핑


직접할당

@Id

id 직접 할당.

@Id
private Long id;


자동 생성 (@GeneratedValue)

IDENTITY 전략

기본키 생성을 데이터베이스에 위임. (주로 MySQL, PostgreSQL, SQL Server, DB2에서 사용)

JPA는 보통 트랜잭션 커밋 시점에서 INSERT SQL이 실행되는데, IDENTITY의 경우에는

em.persist() 시점에 즉시 INSERT SQL을 실행하고, DB에서 식별자를 조회한다.

그래서 IDENTITY 전략의 경우에는 쿼리들을 모아서 flush하는게 불가능하다.

참고로 AUTO_INCREMENT는 데이버테이스에 INSERT SQL을 실행한 이후에 ID값을 알 수 있다.


SEQUENCE 전략

데이터베이스 시퀀스 오브젝트 사용. (ORACLE의 경우 @SequenceGenerator 필요)

데이터베이스 시퀀스는 유일한 값을 순서대로 생성하는 특별한 데이터베이스 Object.

주로 오라클, PostgreSQL, H2 데이터베이스에서 사용한다.

그리고 Sequence 전략은 IDENTITY 전략과는 다르게 버퍼기능 을 지원한다.

@Entity
public class Member {
    @Id @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Long id;
}

동작 방법은 아래와 같다.

순서동작 방법
1em.persist(member) 시점에는 시퀀스 값 없음
2DB에서 시퀀스 값을 조회해서 가져옴
3member에 시퀀스 값을 넣어줌
4영속성 컨텍스트에 저장
5INSERT 쿼리는 안날아감(Commit 때 flush)

추가 적으로 테이블 마다 시퀀스를 따로 관리하고 싶다면 @SequenceGenerator 어노테이션을

사용하면 된다.

@Entity
@SequenceGenerator(
    name = "MEMBER_SEQ_GENERATOR",
    sequenceName = "MEMBER_SEQ",
    initialValue = 1,
    allocationSize = 1
)
public class Member {
    @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "MEMBER_SEQ_GENERATOR")
    private Long id;
}


그런데 여기서 의문점은 2번에서 매번 DB조회를 하면 성능저하가 생기지 않을까

하는 부분이다. 이런 부분을 막고자 allocationSize 라는 속성이 있다.

@Entity
@SequenceGenerator(
    name = "MEMBER_SEQ_GENERATOR",
    sequenceName = "MEMBER_SEQ", //매핑할 데이터베이스 시퀀스 이름
    initialValue = 1, 
    allocationSize = 50)
public class Member {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "MEMBER_SEQ_GENERATOR"
    private Long id;
}

allocationSized을 50으로 지정해두면 처음에 persist할 때 1-51까지 미리 시퀀스를

메모리에 올려둔다. 따라서 50번 까지는 DB에 접근을 하지 않기 때문에 성능 최적화를

할 수 있다.


Table 전략

키 생성 전용 테이블을 하나 만들어서 DB 시퀀스를 흉내내는 전략 (잘 안씀)

장점 : 모든 데이터베이스에 적용 가능

단점 : 성능 이슈

create table MY_SEQUENCES (
    sequence_name varchar(255) not null,
    next_val big int,
    primary key ( sequence_naem )
)
@Entity
@TableGenerator(
    name = "MEMBER_SEQ_GENERATOR",
    table = "MY_SEQUENCES",
    pkColumnValue = "MEMBER_SEQ",
    allocationSize = 1
    )
public class Member {
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE, generator = "MEMBER_SEQ_GENERATOR")
    private Long id; 
}


권장하는 식별자 전략

Long Type + 대체키 + 키 생성 전략 사용

→ 기본 키 제약 조건 : null이면 안된다, 유일해야 한다, 변하면 안된다.

→ 미래까지 이 조건을 만족하는 자연키는 찾기 어렵다. 대체키 사용

→ 비즈니스 키와 관련 없는 키를 사용해야 한다.

자연키 : 주민번호, 전화번호 등등