반응형
Notice
Recent Posts
Recent Comments
관리 메뉴

간단한 개발관련 내용

4장 엔터티 매핑 본문

IT 책/JPA (ORM 표준 JPA 프로그래밍)

4장 엔터티 매핑

vincenzo.dev.82 2024. 11. 19. 13:34
반응형

4.1 @Entity

  • 기본생성자는 필수다
    • 파라미터가 없는 public 또는 protected 생성자로 선언.
    • private은 JPA가 접근할 수 없기 때문에 안된다
  • final 클래스, enum, interface, inner 클래스에는 사용할 수 없다
  • 저장할 필드에 final을 사용하면 안된다

<aside> 💡

JPA는 리플렉션을 사용하여 데이터베이스에서 조회된 데이터를 기반으로 객체를 생성합니다. 리플렉션으로 객체를 생성할 때는 매개변수가 없는 생성자를 호출할 수밖에 없습니다. 따라서 파라미터가 없는 생성자가 없으면 JPA는 해당 엔티티 클래스를 인스턴스화할 수 없습니다.

</aside>

4.2 @Table

  • name
  • catalog
  • schema
  • uniqueConstraints

4.3 다양한 매핑사용

  • @Enumerated : java enum
  • @Temporal : java date
  • @Lob : CLOB, BLOB

 

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

  • create : DROP + CREATE
  • create-drop : : DROP + CREATE + DROP
    • 애플리케이션을 종료할 때 DROP
  • update : DB와 엔터티 비교 후 변경사항만 저장
  • validate : DB와 엔터티 비교 후 차이가 있으면 경고하고 애플리케이션 실행하지 않음.
  • none

<aside> 💡

이름 매핑 전략 변경하기

단어와 단어를 구분할 때 자바 언어는 관계상 roleType과 같이 카멜표기법을 주로 사용하고, 데이터베이스는 관례상 role_type과 같이 언더스코어를 주로 사용한다.

hibernate.ejb.naming_strategy 속성을 사용하면 이름 매핑 전략을 변경할 수 있다. ImprovedNamingStrategy 클래스를 사용해서 테이블 명이나 컬럼 명이 생략되면 자바의 카멜 표기법을 테이블의 언더스코어 표기법으로 매핑한다.

</aside>

 

4.5 DDL 생성기능

  • @Column 의 notnull, length 속성
  • @Table의 uniqueConstraints 속성
  • DDL을 자동 생성할 때만 사용되고 JPA의 실행 로직에는 영향을 주지 않는다

 

4.6 기본 키 매핑

  • 직접할당
    • 기본키를 애플리케이션에서 직접 할당한다
  • 자동생성
    • 대리키 이용방식
      • IDENTITY : 기본 키 생성을 데이터베이스에 위임
      • SEQUENCE : 데이터베이스 시퀀스
      • TABLE : 키 생성 테이블을 이용
  • @Id
    • 기본키를 직접 할당하려면 @Id만 사용하면 되고,
    • 자동 생성 전략을 사용하려면 @Id에 @GeneratedValue를 추가하고 원하는 키 생성전략을 선택하면 된다.

4.6.1 기본 키 직접 할당 전략

  • 자바 기본형
  • 자바 wrapper형
  • String
  • java.util.Date
  • java.sql.Date
  • java.math.BigDecimal
  • java.math.BigInteger

4.6.2 IDENTITY 전략

  • 기본 키 생성을 데이터베이스 위임하는 전략
  • @GeneratedValue(strategy = GenerationType.IDENTITY)
  • 단순하고 사용하기 쉬우나, 배치 삽입(batch insert) 시 효율이 떨어질 수 있습니다.

<aside> 💡

엔터티가 영속 상태가 되려면 식별자가 반드시 필요하다. 그런데 IDENTITY 식별자 생성 전략은 엔터티를 데이터베이스에 저장해야 식별자를 구할 수 있으므로 em.persist()를 호출하는 즉시 INSERT SQL이 데이터베이스에 전달된다. 따라서 이 전략은 트랜잭션을 지원하는 쓰기 지연이 동작하지 않는다.

</aside>

4.6.3 SEQUENCE 전략

  • 시퀀스를 지원하는 오라클, PostgreSQL, DB2, H2 데이터베이스에서 사용할 수 있다
  • @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = “XXX_SEQ_GENERATOR”)
    • Entity에 @SequenceGenerator 선언
  • 성능 최적화가 가능하지만, 시퀀스를 지원하지 않는 데이터베이스에서는 사용할 수 없습니다.

4.6.4 TABLE 전략

  • 모든 데이터베이스에서 사용 가능하지만, 성능이 상대적으로 낮을 수 있습니다.

4.6.5 AUTO 전략

  • 기본 키 생성 전략을 JPA 구현체(Hibernate 등)에 맡깁니다. JPA가 사용하는 데이터베이스에 따라 가장 적합한 방식으로 자동 설정됩니다.
  • 데이터베이스에 맞게 IDENTITY, SEQUENCE, TABLE 중 하나를 자동으로 선택합니다.

4.6.6 기본키 매핑 정리

  • 영속성 컨텍스트는 엔터티를 식별자 값으로 구분하므로 엔터티를 영속 상태로 만들려면 식별자 값이 반드시 있어야 한다. em.persist()를 호출한 직후에 발생하는 일을 식별자 할당 전략별로 정리하면 다음과 같다.
  • 직접할당
    • em.persist()를 호출하기 전에 애플리케이션에서 직접 식별자 값을 할당해야 한다. 만약 식별자 값이 없으면 예외가 발생.
  • SEQUENCE
    • 데이터베이스 시퀀스에서 식별자 값을 획득한 후 영속성 컨텍스트에 저장한다.
  • TABLE
    • 데이터베이스 시퀀스 생성용 테이블에서 식별자 값을 획득한 후 영속성 컨텍스트에 저장한다.
  • IDENTITY
    • 데이터베이스에 엔터티를 저장해서 식별자 값을 획득한 후 영속성 컨텍스트에 저장한다.
    • IDENTITY 전략은 테이블에 데이터를 저장해야 식별자 값을 획득할 수 있다.

<aside> 💡

권장하는 식별자 선택 전략

데이터베이스 기본 키는 다음 3가지 조건을 모두 만족해야 한다.

  1. null값은 허용하지 않는다
  2. 유일해야 한다
  3. 변해선 안 된다

테이블의 기본 키를 선택하는 전략은 크게 2가지가 있다.

  • 자연키(natural key)
    • 비즈니스에 의미가 있는 키
    • 주민등록번호, 이메일, 전화번호
  • 대리키(surrogate key)
    • 비즈니스와 관련없는 임의로 만들어진 키, 대체 키로도 불린다
    • 오라클 시퀀스, auto_increment, 키 생성 테이블 사용

자연키보다느 대리키를 권장한다

비즈니스 환경은 언젠가 변한다

JPA는 모든 엔터티에 일관된 방식으로 대리키 사용을 권장한다

</aside>

 

4.7 필드와 컬럼 매핑 : 레퍼런스

4.7.1 @Column : 컬럼을 매핑한다

  • name
  • insertable
  • updatable
  • table
  • nullable(DDL) : 기본값 true
  • unique(DDL)
  • columnDefinition(DDL) : 데이터베이스 컬럼 정보를 직접 설정
  • length(DDL)
  • precesion, scale(DDL) : BigDecimal 타입

<aside> 💡

@Column 생략

@Column을 생략하게 되면 어떻게 될까? 대부분 @Column 속성의 기본값이 적용되는데, 자바 기본 타입일 때는 nullable 속성에 예외가 있다.

int data1;

Integer data2;

data1과 같은 자바 기본 타입에는 null 값을 입력할 수 없다. data2처럼 객체 타입일 때만 null 값이 허용된다. 따라서 자바 기본 타입인 int를 DDL로 생성할 때는 not null 제약 조건을 추가하는 게 좋다

</aside>

4.7.2 @Enumerated

  • java enum 타입을매핑한다
  • @Enumerated.STRING, @Enumerated.ORDINAL

4.7.3 @Temporal

  • 날짜 타입을 매핑한다

4.7.4 @Lob

  • BLOB, CLOB 타입을 매핑한다

4.7.5 @Transient

  • 특정 필드를 데이터베이스에 매핑하지 않는다

4.7.6 @Access

  • JPA가 엔터티 데이터에 접근하는 방식을 지정한다
  • 2가지 타입을 섞어서 사용해도 된다
  • AccessType.FIELD
    • 필드에 직접 접근, private 이어도 접근 가능
    • @Id를 필드에 사용하면 기본으로 적용
  • AccessType.PROPERTY
    • 프라퍼티 접근, Getter를 사용

4.8 정리

실전 예제 | 1. 요구사항 분석과 기본 매핑

<aside> 💡

데이터 중심 설계의 문제점

책의 예제 방식은 객체 설계를 테이블 설계에 맞춘 방법이다. 특히 테이블의 외래 키를 객체에 그대로 가져온 부분이 문제다. 왜냐하면 관계형 데이터베이스는 연관된 객체를 찾을 때 외래 키를 사용해서 조인하면 되지만 객체에는 조인이라는 기능이 없다. 객체는 연관된 객체를 찾을 때 참조를 사용해야 한다.

하지만 객체에서 참조 대신에 데이터베이스의 외래 키를 그대로 가지고 있으므로 order.getMember()처럼 객체 그래프를 탐색할 수 없고 객체의 특성도 살릴 수 없다.

객체는 외래 키 대신에 참조를 사용해야 한다.

정리하자면 객체는 참조를 사용해서 연관된 객체를 찾고 테이블은 외래 키를 사용해서 연관된 테이블을 찾으므로 둘 사이에는 큰 차이가 있다.

JPA는 객체의 참조와 테이블의 외래 키를 매핑해서 객체에서는 참조를 사용하고 테이블에서는 외래 키를 사용할 수 있도록 한다.

</aside>

반응형