BACK/JPA

[JPA] TIL 6일차 - 엔티티 매핑

연듀 2024. 4. 2. 08:15

@ Entity

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

테이블과 매핑하려면 꼭 필수로 달아줘야 한다.

 

JPA 스팩상 기본 생성자(public or protected) 가 필수로 있어야 한다.

final 클래스, inner클래스, enum, interface로 사용할 수 없다.

DB에 저장할 필드는 final을 사용하면 안된다.

엔티티 이름은 기본 값으로 클래스 이름을 그대로 사용한다.

 

 

@Table

엔티티와 매핑할 테이블을 지정한다.

@Table(name=”DB에서 매핑할 테이블 이름”)

기본값: 엔티티 이름을 사용

 

 

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

 

JPA는 애플리케이션 로딩 시점에 DB테이블을 생성하는 기능을 지원해준다.

객체 매핑을 해놓으면 자동으로 테이블을 create 해준다.

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

이렇게 생성된 DDL은 개발 서버에서만 사용하도록 한다.

생성된 DDL은 운영 서버에서 사용하지 않거나, 사용한다면 적절히 다듬어서 사용한다.

 

 

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

 

hibernate.hbm2ddl.auto

create: 기존 테이블을 삭제 후 다시 생성(DROP → CREATE)

create-drop: create와 같으나 애플리케이션 종료 시점에 테이블을 DROP (보통 테스트케이스 때 사용)

update: 변경분만 반영 (컬럼이 추가 된 것만 적용, 삭제된 건 적용 안됨), (운영 DB에는 사용하면 안됨) 

validate: 엔티티와 테이블이 정상 매핑되었는지만 확인(일치하지 않은 매핑이 있으면 오류가 발생)

none: 사용하지 않음

 

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

개발 초기 단계: create 또는 update

테스트 서버: update 또는 validate

스테이징과 운영서버: validate 또는 none

 

DDL 생성 기능

제약 조건 추가: 회원 이름은 필수, 10자가 초과되면 안됨

@Column(nullable = false, length = 10)

 

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

 

 

필드와 컬럼 매핑

 

@Entity
public class Member {
    @Id // PK
    private Long id;
    
    @Column(name = "name", nullable = false) // DB에 쓰고 싶은 컬럼 이름
    private String username;
    
    private Integer age;
    
    @Enumerated(EnumType.STRING) // 객체에 Enum 타입을 사용 할 때, 무조건 string으로 사용할 것
    private RoleType roleType;
    
    @Temporal(TemporalType.TIMESTAMP) // 날짜 타입 (DATE, TIME, TIMESTAMP)
    private Date createdDate;
    
    @Temporal(TemporalType.TIMESTAMP) // LocalDate, LocalDateTime을 사용하면 생략 가능
    private Date lastModifiedDate;
    
    @Lob // varchar를 넘어서는 큰 컨텐츠. 문자면 clob, 나머지는 blob 으로 매핑
    private String description;

    @Transient // 메모리에서만 사용, 특정 필드를 컬럼에 매핑하지 않음
    private int tmp;

    public Member() {
    }
    // getter, setter...
}

 

 

@Column
컬럼 매핑
@Temporal
날짜 타입 매핑
@Enumerated
enum 타입 매핑
@Lob
BLOB, CLOB 매핑
@Transient
특정 필드를 컬럼에 매핑하지 않음(매핑 무시)

 

기본키 매핑

 

기본키 매핑 어노테이션: @Id, @GeneratedValue

 

직접 할당: @Id만 사용

자동생성: @Id + @GeneratedValue

 

ex) @GeneratedValue(strategy = GenerationType.IDENTITY)

 

IDENTITY: 기본 키 생성을 데이터베이스에 위임, MySQL

 

id에 값을 직접 넣으면 안된다. null로 날라오면 DB에서 값을 세팅해준다.

그럼 DB에 값이 넣어져야만 영속성 컨텍스트에서 id를 알 수 있는 문제가 생기므로, 

(영속성 컨텍스트에 저장하려면 항상 PK가 있어야 한다)

IDENTITY같은 경우에는 예외적으로 커밋하는 시점이 아니라 em.persist를 할 때 insert문이 날라가 DB에 id 값이 들어가게 된다.

따라서 IDENTITY의 경우에 모아서 insert하는게 불가능하다.

(AUTO_INCREMENT는 데이터베이스에 insert sql을 실행 한 이후에 ID값을 알 수 있음)

=> IDENTITY 전략은 em.persist() 시점에 insert sql 실행하고 DB에서 식별자를 조회

 

 

SEQUENCE: 데이터베이스 시퀀스 오브젝트 사용, Oracle, @SequenceGenerator 필요

 

em.persist시 call next value for MEMBER_SEQ로 쿼리가 나간다.

(데이터베이스에 MEMBER_SEQ의 다음값 달라는 뜻)

그럼 DB에서 값을 얻어와 아이디에 값을 넣어줘 영속성 컨텍스트에 저장한다. (실제 insert쿼리는 이후 커밋 할 때 호출)

⇒ SEQUENCE 방식은 모았다가 write하는 버퍼링이 가능하다.

 

 

식별자 전략 

기본키 제약 조건: null 이 아니고, 유일하고, 변하면 안된다.

Long 형 + 대체키 + 키 생성전략을 조합해 사용하도록 한다.

 

 

 

 

 

 

인프런 자바 ORM 표준 JPA 프로그래밍 - 기본편을 수강하고 정리한 글입니다.

https://www.inflearn.com/course/ORM-JPA-Basic