JPA - 엔티티 매핑

HyeBin, Park·2022년 4월 16일
0
post-thumbnail

엔티티 매핑

-> JPA를 사용하는 데 가장 중요한 일은 엔티티와 테이블을 정확히 매핑 하는 것

  • 엔티티는 데이터베이스나 SQL상에 존재하지 않는 일종의 개념이다.
  • 테이블은 데이터베이스나 SQL에 실제로 존재하고 물리적인 구조를 가지고 있다.

@Entity

  • @Entity가 붙은 클래스는 JPA가 관리하는 것으로 엔티티라 부른다.

    속성기능기본값
    nameJPA에서 사용할 엔티티 이름을 지정한다.
    보통 기본값인 클래스 이름을 사용한다.
    다른 패키지에 이름이 같은 엔티티 클래스가 있다면
    이름을 지정해서 충돌을 방지
    클래스의 이름을 그대로 사용한다.
  • 기본 생성자는 필수(파라미터가 없는 Public또는 protected 생성자)

    • JPA가 엔티티 객체를 생성할 때 기본 생성자를 사용하므로 반드시 필요하다.
    • 생성자가 하나도 없을 경우에 기본 생성자를 자동으로 만들지만, 하나 이상일 경우 자동 생성 X
  • final 클래스, enum, interface, inner 클래스에는 사용할 수 없다.

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

@Table

  • 엔티티와 매핑할 테이블을 지정한다. 생략시 매핑한 엔티티 이름을 테이블 이름으로 사용
    속성기능기본값
    name매핑할 테이블 이름엔티티 이름
    catalogcatalog 기능이 있는 데이터베이스에서 catalog를 매핑한다.
    schemaschema 기능이 있는 데이터베이스에서 schema를 매핑한다.
    uniqueConstraints
    (DDL)
    DDL 생성 시 유니크 제약조건을 만든다. 복합 유니크 제약 조건도 만들 수 있다.
    스키마 자동 생성 기능을 사용해서 DDL을 만들 때만 사용
  • schema
    => Database의 구조와 제약조건에 관한 전반적인 명세를 기술한 것으로 데이터 사전에 저장
  • catalog (데이터 사전)
    => DBMS에서 지원하는 모든 데이터 객체에 대한 정의나 명세에 관한 정보를 유지 관리하는 시스템 테이블이다.

필드와 컬럼 매핑

@Column

  • 객체 필드를 테이블 컬럼에 매핑한다.
    속성기능기본값
    name필드와 매핑할 테이블의 컬럼 이름객체의 필드 이름
    nullable(DDL)null값 허용 여부 설정true
    unique(DDL)한 컬럼에 유니크 제약조건을 걸 때 사용
    두컬럼 이상에 유니크 제약조건 사용시 @Table(uniqueConstraints=)를 사용
    columnDefinition(DDL)데이터베이스 컬럼 정보를 직접 줄 수 있다.
    @Column(columnDefinition = "boolean default false")
    필드의 자바 타입과
    방언 정보를 사용해서
    적절한 컬럼 타입을 생성
    length(DDL)문자 길이 제약 조건, String 타입에만 사용255
    precision, scale
    (DDL)
    BigDecimal, BigInteger 타입에서 사용
    precision : 소수점을 포함한 전체 자릿수
    scale : 소수의 자릿수
    => double, float타입에 적용 x, 아주 큰 숫자나 정밀한 소수를 다룰때 사용
    precision = 19
    scale = 2

  • BigDecimal : Java 언어에서 실수를 정밀하게 저장하고 표현할 수 있는 유일한 방법 (돈을 다룰 때 필수)
  • @Column 생략시 nullable 속성 예외
    • 자바 기본 타입에서는 nullable = false
    • 객체 타입에서는 nullable = true

@Enumertaed

  • 자바 enum 타입을 매핑할 때 사용

    속성기능기본값
    value- EnumType.ORDINAL : enum 순서를 DB에 저장
    - EnumType.STRING : enum 이름을 DB에 저장
    EnumType.ORDINAL
  • EnumType.ORDINAL

    • 장점 : DB에 저장되는 데이터 크기가 작다.
    • 단점 : 이미 저장된 enum의 순서를 변경할 수 없다.
  • EnumType.STRING

    • 장점 : 저장된 enum의 순서가 바뀌거나 추가되어도 안전하다.
    • 단점 : DB에 저장되는 데이터의 크기가 ORDINAL에 비해서 크다.

    @Converter : AttributeConverter<X,Y> 참고 참고

@Temporal

  • 날짜 타입을 매핑할 때 사용한다.
    속성기능기본값
    value- TemporalType.DATE : 날짜, DB의 date 타입과 매핑
    - TemporalType.TIME : 시간, DB의 time 타입과 매핑
    - TemporalType.TIMESTAMP : 날짜와 시간, DB timestamp 타입과 매핑
    EnumType.ORDINAL

@Lob

  • 데이터베이스 BLOB, CLOB 타입과 매핑한다.
  • 지정할 수 있는 속성이 없다.
  • 필드 타입에 따라 문자열이면 CLOB로 매핑, 나머지는 BLOB로 매핑
  • CLOB (Character Large Object) : 대용량의 텍스트 파일
  • BLOB (Binary Large Object) : 이미지, 동영상, MP3 등 데이터 파일

@Transient

  • DB에 저장하지 않고 조회하지도 않음, 객체에 임시로 어떤 값을 보관하고 싶을 때 사용
    ##자바에서 transient : 직렬화 시 특정 멤버변수를 무시하고 싶은 경우 사용하는 키워드

@Access

  • JPA가 엔티티 데이터에 접근하는 방식을 지정
    속성기능기본값
    value- AccessType.FILED : 필드에 직접 접근한다.
    private이어도 접근할 수 있다.
    - AccessType.PROPERTY : 접근자를 사용한다.
    @Id 위치를 기준으로 설정

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

<!--하이버네이트의 HBM2DDL-->
<property name="hibernate.hbm2ddl.auto" value="속성"/>
<!--DDL 콘솔에 출력-->
<property name="hibernate.show_sql" value="true"/> 
<!--JPA2.1 부터 표준으로 지원, UPDATE, VALIDATE 옵션 지원 X -->
<property name="javax.persistence.schema-genertaion.dtabase.action" value="속성"/>
  • JPA는 클래스의 매핑정보와 데이터베이스 방언을 사용해서 데이터베이스 스키마를 생성한다.

  • 애플리케이션 실행 시점에 DB 테이블이 자동으로 생성되어 개발자의 수고를 덜 수 있다.

  • 완벽하지 않으므로 개발환경에서 사용하거나 매핑을 어떻게 해야하는지 참고 정도로만 사용

    속성기능
    createDROP + CREATE
    create-dropDROP + CREATE + DROP
    updateDB 테이블과 엔티티 매핑정보를 비교해서 변경 사항만 수정
    validateDB 테이블과 엔티티 매핑정보를 비교해서 차이가 있으면 경고를 남기고 실행 X
    none자동 생성 기능을 사용하지 않음, 유효하지않은 옵션 값

하이버네이트 이름 매핑

<property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy" />
  • 자바는 카멜표기법을 사용하고 DB는 언더스코어를 사용해서 name을 따로 명시해줘야한다.
  • 하지만 위의 하이버네이트 속성을 사용하면 테이블명이나 컬럼명 생략시 카멜표기법을 언더스코어 표기법으로 매핑해준다 !
  • 하이버네이트 5부터는 naming_strategy를 사용하지 않는다고함 참고

기본 키 매핑

1) 직접 할당 : 기본 키를 애플리케이션에서 직접 할당한다.

  • @Id로 매핑한다.
  • 가능한 타입 : 자바 기본형, 자바 wrapper형, String, BigDecimal, BigInteger
  • java.util.Date : 1970년 1월 1일 00:00:00 GMT 이후 정확한 밀리 초로 현재 순간을 알려줌
  • java.sql.Date : SQL 날짜에는 년, 월, 일만 포함되며 시간 및 시간대는 없음
    => sql이 util을 상속받음
  • 식별자 값 없이 저장하면 예외가 발생한다. javax.persistence.PersistenceException

2) 자동 생성 : 대리 키 사용 방식

<property name="hibernate.id.new_generator_mappings" value="true"/>
  • IDENTITY : 기본 키 생성을 DB에 위임한다.

    • MySQL의 AUTO_INCREMENT
    • @GeneratedValue(strategy = GenerationType.IDENTITY)
    • persist() 호출 즉시 INSERT SQL이 DB에 전달되어 쓰기 지연이 동작하지 않는다.
      => 엔티티가 영속상태가 되려면 식별자가 반드시 필요하기 때문에
    • Statement.getGenertaedKeys()를 사용하면 데이터 저장과 동시에 기본 키 값도 얻을 수 있음
      => 하이버네이트는 DB와 한 번만 통신한다.
      => ResultSet에 자동 생성된 키의 데이터 유형은 해당 도메인의 데이터 유형에 상관 없이 DECIMAL이다.
  • SEQUENCE : DB 시퀀스를 사용해서 기본 키를 할당한다. (오라클, H2)

      // 시퀀스 생성
      CREATE SEQUENCE BOARD_SEQ START WITH 1 INCREMENT BY 1;
    
      // 시퀀스 매핑 
      @Entity
      @SequenceGenerator(
        name = "BOARD_SEQ_GENERATOR",
        sequenceName = "BOARD_SEQ",
        initialValue = 1, allocationSize = 1)
      public class Board {
    
        @Id
        @GeneratedValue(strategy = GenerationType.SEQUENCE,
                            generator = "BOARD_SEQ_GENERATOR")
        private Long id;
      }
    
    // DDL
    create sequence [sequenceName] start with [initialValue] increment by [allocationSize]
    • 사용 코드는 IDENTITY 전략과 같지만 내부 동작 방식은 다르다.

    • em.persist() 호출시 시퀀스를 사용해서 식별자를 조회하고, 그 식별자를 엔티티에 할당한 후에 엔티티를 영속성 컨텍스트에 저장한다.

    • @SequenceGenerator 속성

      속성기능기본 값
      name식별자 생성기 이름NOT NULL !
      sequenceName데이터베이스에 등록되어 잇는 시퀀스 이름hibernate_sequence
      initialValueDDL 생성 시에만 사용됨. 처음 시작하는 수1
      allocationSize시퀀스 한 번 호출에 증가하는 수(성능 최적화에 사용)50
      catalog, schemaDB catalog, schema 이름
      • allocationSize 알고리즘 참고
  • TABLE : 키 생성 테이블을 사용한다.

    // 키 생성 DDL
    create table MY_SEQUENCES (
    	sequence_name varchar(255) not null,
    	next_val bigint,
    	primary key (sequence_name)
    )
    
    // 키 생성기 등록
      @Entity
      @TableGenerator(
        name = "BOARD_SEQ_GENERATOR",
        sequenceName = "MY_SEQUENCES",
        pkColumnValue = "BOARD_SEQ", allocationSize = 1)
      public class Board {
    
        @Id
        @GeneratedValue(strategy = GenerationType.TABLE,
        				generator = "BOARD_SEQ_GENERATOR")
        private Long id;
    }
    • 테이블을 사용하므로 모든 DB에 적용할 수 있다.
    • 값을 조회하면서 SELECT 쿼리를 사용하고
    • 키 생성기를 사용할 때마다 next_val 컬럼 값을 증가시키기위해 UPDATE 쿼리를 사용한다.
    • 최적화를 위해서 @TableGenerator.allocationSize를 사용한다.

3) AUTO 전략

  • GenerationType.AUTO는 선택한 DB 방언에 따라 전략을 하나 자동으로 선택한다.
  • 기본 값은 AUTO
  • DB를 변경해도 코드를 수정할 필요가 없고, 개발 초기 단계나 프로토타입 개발 시 편리하다.
  • SEQUENCE나 TABLE 전략이 선택되면 시퀀스나 키 생성용 테이블을 미리 만들어 두어야 한다.
    • 스키마 자동 생성 기능 사용 시 하이버네이트가 기본값을 사용해 만들어준다.

식별자 선택

  • DB 기본 키가 만족해야하는 조건
    1. NULL 값은 허용하지 않음
    2. 유일해야한다.
    3. 변해선 안 된다.
  • 자연 키 VS 대리 키
    • 자연 키 : 비즈니스에 의미가 있는 키 EX) 주민등록번호, 이메일, 전화번호
    • 대리 키(대체 키) : 비즈니스와 관련 없는 임의로 만들어진 키
      => 대리 키 사용 권장 !

0개의 댓글