엔티티 매핑

식빵·2021년 12월 28일
0

JPA 이론 및 실습

목록 보기
6/17

이론서나 인강 모두 너무 래퍼런스의 느낌이 강해서 딱히 자세히 쓰지 않겠다.
그냥 내가 중요하다고 생각한 것들만 가져다 정리했다.


🍀 @Entity

작성시에 유의할 점만 알자.

  • 기본 생성자(public + protected)는 필수
  • 저장할 필드는 final X
  • final 클래스, enum, interface, inner 클래스 사용 X



🍀 DDL 자동 생성 및 실행

애플리케이션 실행 시점에 데이터베이스 DDL을 자동 생성해주는 기능을 제공한다.

persistence.xml 파일에서 아래 항목만 잘 수정하면 된다.
<property name="hibernate.hbm2ddl.auto" value="{여기에 아래 목록 중 하나 선택}">

  • create: DROP + CREATE
  • create-drop : DROP + CREATE + DROP
  • update : table과 entity 비교 후, 변경사항만 적용
  • validate : table 과 entity를 비교해서 매핑정보가 올바르지 않으면 경고 날리고 app 실행 X
  • none : 사실 이런 값은 없다. 관례적으로 아무 적용도 안 할 때 none을 사용



이름 매핑 전략 변경하기

  • 기본적으로는 JPA는 엔티티 필드명, 테이블 이름 그대로 실제 DB Table 과 매핑
  • 하지만 Java 에서는 CamelCase, 데이터베이스의 Snake Case 를 사용한 naming 대다수
  • 이런 매핑 전략을 하이버네이트가 제공
  • 적용 방법: persistence.xml 에 property 추가
    <property name="hibernate.physical_naming_strategy" value="org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy"/>
  • physical_naming_strategy 은 명시적/암묵적 컬럼명을 지정해도 항상 반영

참고로 CamelCaseToUnderscoresNamingStrategy 전략은 스프링의 SpringPhysicalNamingStrategy을 뱃겨온 것이다.릴리스 공지글에 나와 있다.



DDL 생성 기능

  • ex: Column(nullable=false, length=10)
  • 스키마 자동 생성시 DDL에 제약 조건이나 추가적인 뭔가를 줄 때 사용하는 것
  • DDL을 자동 생성할 때만 사용되고 JPA 실행 로직(= 런타임)에는 영향을 주지 않음
  • 직접 DDL을 만들었다면 DDL 생성 기능을 사용 안해도 됨
  • 하지만 해두면 개발자가 엔티티만 보고 테이블의 제약 조건을 빨리 파악할 수 있다는 장점이 있음




🍀 기본 키 매핑


"직접 할당" vs "자동 생성"

  • 직접 할당: 애플리케이션에서 직접 할당, @Id 사용
  • 자동 생성 : @Id + @GeneratedValue
    • IDENTITY: AUTO_INCREMENT 와 동일
    • SEQUENCE: 데이터베이스 시퀀스를 사용
    • TABLE: 키 생성 테이블 사용

자동생성 전략

  • AUTO : DB 방언에 따라 자동으로 IDENTITY, TABLE, SEQUENCE 중 하나 사용
  • IDENTITY : 그냥 MySQL의 auto_increment라고 생각하면 된다.
  • SEQUENCE : 시퀀스 사용
  • TABLE : 기본 키 생성용 테이블 사용

1. IDENTITY 전략 상세

엔티티 코드에서 딱히 뭔가를 설정하지 않아도 된다.


2. SEQUENCE 전략 상세

@Entity
@SequenceGenerator(
    name = "member_seq_generator", // JPA 내에서만 사용할 시퀀스의 이름
	sequenceName = "member_seq" // 실제 DB에 적용할 시퀀스 이름
)
public class Member {

    @Id 
    @GeneratedValue(strategy = GenerationType.SEQUENCE,
    		    generator = "member_seq_generator")
    private String id;

    // ... 생략   
}

참고1.

  • @SequenceGenerator를 사용하면 allocationSize 가 기본으로 50
  • create seqeunce start with 1 increment 50라고 생각하면 됨
  • allocationSize를 사용하면 매번 시퀀스 번호를 얻을 필요없이 미리 1~50까지 쌓아놓고 사용
  • 50개를 다 쓰면 새롭게 51~100 까지 값을 읽어옴

참고2.
allocationSize 는 실제 Database 에서 생성한 increment 양과 똑같이 작성해야 에러가 안 생긴다.
반면에 initialValue 는 시퀀스 DDL 자동 생성시에만 쓰인다.


3. TABLE 전략 상세

  • 키 생성 전용 테이블 생성하고 데이터베이스 시퀀스를 모방
  • 모든 데이터베이스에 적용 가능하지만 성능은 그닥
@Entity
@TableGenerator(
        name = "SOME_SEQ_GENERATOR",
        table = "TABLE_SEQUENCES",
        pkColumnValue = "SOME_SEQ",
        allocationSize = 1
)
public class SomeEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE,
                    generator = "SOME_SEQ_GENERATOR")
    private Long id;

    private String name;

    private Integer age;

}

참고
매핑할 DDL, 테이블명 {table}

{pkColumnName}{valueColumnName}
{pkColumnValue}{initialValue}



생성 전략과 영속성 컨텍스트

영속성 컨텍스트에 엔티티를 저장되기 위해서는 반드시 식별자 값(@Id)가 반드시 필요하다.
그리고 [IDENTITY / SEQUENCE] 전략은 서로 다른 저장 방식을 갖는다.
지금부터 그 차이를 알아본다.


1. IDENTITY

  • IDENTITY (= Auto Increment) 전략은 INSERT 쿼리를 실행해야 식별자값 획득
  • 트랜잭션 커밋시 insert 쿼리 수행(= JPA 기본방식) 하지 않고, em.persist() 할 때 바로 쿼리 실행하여 기본키 값 받아옴

2. SEQUENCE

  • em.persist 호출 시 시퀀스에서 값을 얻어서 식별자(@Id)로 사용
    • ex: call next value for MEMBER_SEQ
  • 트랜잭션 커밋시에 JPA 기본 방식대로 flush 를 수행하여 최종 insert 쿼리 날라감

참고
sequence 전략은 em.persist 하나당 2번 쿼리가 날라가는 것이 불만족스러울 수 있다.
하지만 이것은 allocationSize를 통해서 미리 값을 받아오면 해소가 된다.
참고로 사전에 미리 값을 올려두고 사용하기 여러 WAS가 있어도 동시성 문제는 없다



권장 식별자 전략

  • 기본 키 제약 조건: null 아님, 유일, 변하면 안된다.
  • 미래까지 이 조건을 만족하는 자연키는 찾기 어렵다. 대리키(대체키)를 사용하자.
  • 예를 들어 주민등록번호도 기본 키로 적절하지 않다.
  • 권장 : Long형 + 대체키 + 키 생성 전략 사용



참고

자바 ORM 표준 JPA 프로그래밍
인프런 JPA 관련 로드맵

profile
백엔드를 계속 배우고 있는 개발자입니다 😊

0개의 댓글