Skip to content

chap 4 minseong

MIN SEONG edited this page May 6, 2020 · 1 revision
  • JPA 사용시 중요한 것 : 엔티티(Entity)와 테이블(Table) 매핑
  • JPA의 매핑 어노테이션
    • 객체와 테이블 매핑 : @Entity, @Table
    • 기본 키 매핑 : @Id
    • 필드와 컬럼 매핑 : @Column
    • 연관관계 매핑 : @ManyToOne, @JoinColumn

4.1 @Entity

  • JPA를 사용해서 테이블과 매핑하는 클래스
  • @Entity 속성
속성 기능 기본값
name JPA에서 사용할 엔티티 이름 지정
다른 패키지와 이름을 다르게 해야 한다
설정하지 않으면 클래스이름을 그대로 사용
  • @Entity 적용 시 주의사항
    • 기본 생성자 필수(파라미터가 없는 public, protected)
    • final, enum, interface, inner 클래스 사용 불가

4.2 @Table

  • 엔티티와 매핑할 테이블을 지정
  • @Table 속성
속성 기능 기본값
name 매핑할 테이블 이름 엔티티 이름을 사용
catalog 데이터베이스에 catalog 매핑
schema 데이터베이스에 schema 매핑
uniqueConstraints(DDL) DDL 생성 시에 유니크 제약 조건 생성

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

  • JPA는 데이터베이스 스키마를 자동으로 생성하는 기능을 지원하여 클래스 매핑 정보를 보면 테이블에 어떤 컬럼을 사용하는지 알 수 있다
  • persistence.xml에서 hibernate.hbm2ddl.auto 값 설정
    • value="create" 설정시 애플리케이션 실행 시점에 데이터베이스 테이블이 있는지 확인하여 자동으로 생성해준다.
      • 개발자가 테이블을 직접 생성할 필요가 없음
      • 운영 환경에서 사용할만큼 완벽하지는 않으므로 개발 환경이나 참고용으로 사용하는 것이 좋음
    • 설정시 콘솔에서 해당 테이블 생성 DDL을 출력
  • 자동 생성되는 DDL은 데이터베이스 방언에 따라 적절한 타입으로 생성
  • hibernate.hbm2ddl.auto 속성
옵션 설명
create 기존 테이블을 삭제하고 새로 생성(DROP + CREATE)
create-drop create 속성 + 애플리케이션 종료시
생성한 DDL 제거(DROP + CREATE + DROP)
update 데이터베이스의 테이블과 엔티티 매핑정보를 비교해서
변경 사항만 수정
validate 데이터베이스의 테이블과 엔티티 매핑정보를 비교해서
차이가 있으면 경고를 남기고 애플리캐이션을 실행하지 않음
DDL을 수정하지 않는다
none 자동 생성 기능을 사용하지 않으려면
hibernate.hbm2ddl.auto 속성을 삭제한다
  • JPA 2.1 버전부터는 스키마 자동 생성 기능을 표준으로 지원
   // persistence.xml
   <property name="javax.persistence.schema-generation.database.action" value="drop-and-create" />
  • none, create, drop-and-create, drop
  • hibernate.ejb.naming_strategy 속성 사용시 테이블명이나 컬럼명이 생략되어도 테이블 컬럼을 언더스코어 표기법으로 매핑

4.5 DDL 생성 기능

  • @Colume 매핑정보의 속성 값들
    • nullable : not null 제약 조건(false이면 not null)
    • length : 문자 크기 지정
  • @Table의 uniqueConstraints 속성
// Member.java

 @Entity(name="Member")
 @Table(name="MEMBER", uniqueConstraints = { @UniqueConstraint( // 추가
   name = "NAME_AGE_UNIQUE",
   columeNames = { "NAME", "AGE" } ) } )

 public class Member {
   ...
 }
  • DDL 생성 기능들은 DDL을 자동 생성할 때만 사용되고 JPA 실행 로직에는 영향을 주지 않음

4.6 기본 키 매핑

  • JPA가 제공하는 데이터베이스 기본 키 생성 전략
    • 직접 할당 : 기본 키를 애플리케이션에서 직접 할당(`@Id 사용)
    • 자동 생성 : 대리 키 사용 방식. 데이터베이스가 생성해주는 값을 사용
      • IDENTITY : 기본 키 생성을 데이터베이스에 위임
      • SEQUENCE : 데이터베이스 시퀀스를 사용해서 기본 키를 할당
      • TABLE : 키 생성 테이블 사용
    • 자동 생성 전략의 경우 데이터베이스 벤더마다 지원 방식이 다르므로 방법이 다양해짐
      • 오라클의 시퀀스, MySQL의 AUTO_INCREMENT
    • IDENTITY, SEQUENCE 전략의 경우 사용하는 데이터베이스에 의존적
    • TABLE 전략의 경우 테이블을 활용하므로 모든 데이터베이스에서 사용
    • persistence.xml에 hibrenate.id.new_generator_mappings=true 속성 추가

4.6.1 기본 키 직접 할당 전략

  • @Id 적용 가능 자바 타입 : 자바 기본형, 자바 래퍼형(Wrapper), String, java.util.Date, java.sql.Date, java.math.BigDecimal, java.math.BigInteger
  • 기본 키 직접 할당 전략은 persist()로 엔티티를 저장하기 전에 애플리케이션에서 기본 키를 직접 할당하는 방법
  • 기본 키를 식별자 값 없이 저장 시 javax.persistence.PersistenceException 예외 발생

4.6.2 IDENTITY 전략

  • 기본 키 생성을 데이터베이스에 위임하는 전략
  • MySQL, PostgreSQL, SQL Server, DB2에서 사용
  • @GeneratedValue의 strategy 속성 값을 GenerationType.IDENTITY로 지정
  • JPA에서 IDENTITY 전략은 데이터를 데이터베이스에 INSERT한 후에 기본 키 값을 조회할 수 있음
  • JDBC3에 추가된 Statement.getGeneratedKeys() 사용 시 데이터를 저장하면서 동시에 생성된 기본 키 값을 얻어옴
  • IDENTITY 전략은 엔티티를 데이터베이스에 저장해야 식별자를 구할 수 있으므로 트랜잭션을 지원하는 쓰기 지연이 동작하지 않음
// Board.java

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

4.6.3 SEQUENCE 전략

  • 데이터베이스 시퀀스 : 유일한 값을 순서대로 생성하는 데이터베이스 오브젝트
  • 오라클, PostgreSQL, DB2, H2에서 사용
  • persist() 호출 시 먼저 데이터베이스 시퀀스를 사용해서 식별자를 조회하여 엔티티에 할당한 후 영속성 컨텍스트에 저장한다. 그 후 트랜잭션 커밋시 플러시가 일어나 엔티티를 데이터베이스에 저장한다.
  • JPA 표준 명세에서는 sequenceName의 기본값을 JPA 구현체가 정의하도록 함
  • @SequenceGenerator 속성
속성 기능 기본값
name 식별자 생성기 이름 필수
sqeuenceName 데이터베이스에 등록되어 있는 시퀀스 이름 hibernate_sequence
initialValue DDL 생성 시에만 사용됨, 시퀀스 DDL을 생성할 때
처음 시작하는 수를 지정한다.
1
allocationSize 시퀀스 한 번 호출에 증가하는 수
(성능 최적화에 사용됨)
50
catalog, schema 데이터베이스 catalog, schema 이름
// Board2.java

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

4.6.4 TABLE 전략

  • 키 생성 전용 테이블을 하나 만들고 여기에 이름과 값으로 사용할 컬럼을 만들어 데이터베이스 시퀀스를 흉내내는 전략
    create table MY_SEQUENCE (
        sequence_name varchar(255) not null,
        next_val bigint,
        primary key ( sequence_name )
    )
  • JPA 표준 명세에서는 table, pkColumnName, valueColumnName의 기본값을 JPA 구현체가 정의하도록 함

  • SEQUENCE 전략과 비교해서 UPDATE를 위해 데이터베이스와 한 번 더 통신하는 단점이 있음

  • @TableGenerator 속성 정리

속성 기능 기본값
name 식별자 생성기 이름 필수
table 키생성 테이블명 hibernate_sequence
pkColumnName 시퀀스 컬럼명 sequence_name
valueColumnName 시퀀스 값 컬럼명 next_val
pkColumnValue 키로 사용할 값 이름 엔티티 이름
initialvalue 초기 값, 마지막으로 생성된 값이 기준이다. 0
allocationsize 시퀀스 한 번 호출에 증가하는 수
(성능 최적화에 사용됨)
50
catalog, schema 데이터베이스 catalog, schema 이름
uniqueConstraints(DDL) 유니크 제약 조건을 지정할 수 있다.
// Board3.java
    @Entity
    @TableGenerator(
            name = "BOARD_SEQ_GENERATOR",
            table = "MY_SEQUENCES",
            pkColumnValue = "BOARD_SEQ", allocationSize = 1 )
    public class Board3 {
    
        @Id
        @GeneratedValue(strategy = GenerationType.TABLE,
                        generator = "BOARD_SEQ_GENERATOR")
        private Long id;
        ...
    }

4.6.5 AUTO 전략

  • GenerationType.AUTO : 선택한 데이터베이스 방언에 따라 세 전략 중 하나를 자동으로 선택
  • 데이터베이스를 변경해도 코드를 수정할 필요가 없음
    • SEQUENCE, TABLE 전략이 선택되면 시퀀스나 키 생성용 테이블을 미리 만들어 두어야 함
    • 스키마 자동 생성 기능을 사용하면 하이버네이트가 기본값을 사용해서 적절한 시퀀스나 키 생성용 테이블을 만들어 줌
// Board4.java
    @Entity
    public class Board4 {
    
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private Long id;
        ...
    }

4.6.6 기본 키 매핑 정리

  • 직접 할당 : persist()를 호출하기 전에 애플리케이션에서 직접 식별자 값을 할당해야 한다. 만약 식별자 값이 없으면 예외가 발생
  • SEQUENCE : 데이터베이스 시퀀스에서 식별자 값을 획득한 후 영속성 컨텍스트에 저장
  • TABLE : 데이터베이스 시퀀스 생성용 테이블에서 식별자 값을 획득한 후 영속성 컨텍스트에 저장
  • IDENTITY : 데이터베이스에 엔티티를 저장해서 식별자 값을 획득한 후 영속성 컨텍스트에 저장

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

4.7.1 @Column

  • 객체 필드를 테이블 컬럼에 매핑
  • @Column 속성 정리
속성 기능 기본값
name 필드와 매핑할 테이블의 컬럼 이름 객체의 필드 이름
insertable, updatable 등록, 변경 가능 여부 TRUE
nullable(DDL) null 값의 허용 여부를 설정한다. false로 설정하면 DDL 생성 시에 not null 제약조건이 붙는다.
unique(DDL) @Table의 uniqueConstraints와 같지만 한 컬럼에 간단히 유니크 제약조건을 걸 때 사용한다.
columnDefinition(DDL) 데이터베이스 컬럼 정보를 직접 줄 수 있다.
length(DDL) 문자 길이 제약조건, String 타입에만 사용한다. 255
precision, scale(DDL) BigDecimal 타입에서 사용한다(BigInteger도 사용할 수 있다).
precision은 소수점을 포함한 전체 자릿수를, scale은 소수의 자릿수다.
참고로 double, float 타입에는 적용되지 않는다.
아주 큰 숫자나 정밀한 소수를 다루어야 할 때만 사용한다.
precision=19, scale=2
  • @Column 생략
    • 자바의 기본 타입(int)에는 null 입력이 불가, 객체 타입(Integer)일때는 null 입력 허용
    • JPA에서는 DDL 생성 기능을 사용시 기본 타입에 not null 제약 조건을 추가
    • @Column 사용시 nullable = true가 기본값임을 유의

4.7.2 @Enumerated

  • enum 타입 매핑에 사용
  • @Enumerated 사용 예
    • EnumType.ORDINAL(기본값) : enum에 정의된 순서대로 0부터 순서값을 저장
      • 장점 : 데이터베이스에 저장되는 데이터 크기가 작다
      • 단점 : 이미 저장된 enum의 순서를 변경할 수 없다
    • EnumType.STRING : enum에 저장된 문자 그대로 데이터베이스에 저장
      • 장점 : 저장된 enum의 순서가 바뀌거나 추가되어도 안전하다
      • 단점 : 데이터베이스에 저장되는 데이터 크기가 ORDINAL에 비해서 크다

4.7.3 @Temporal

  • 날짜 타입(Date, Calendar)를 매핑할 때 사용한다.
  • @Temporal 사용 예
    • TemporalType.DATE : 날짜, 데이터베이스 date 타입과 매핑(예: 2013–10–11)
    • TemporalType.TIME: 시간, 데이터베이스 time 타입과 매핑(예: 11:11:11)
    • TemporalType.TIMESTAMP: 날짜와 시간, 데이터베이스 timestamp 타입과 매핑(예: 2013–10–11 11:11:11)

4.7.4 @Lob

  • 데이터베이스 BLOB, CLOB 타입과 매핑
  • @Lob에는 지정할 수 있는 속성이 없다.
  • 매핑하는 필드 타입이 문자면 CLOB 매핑, 나머지는 BLOB 매핑
    • CLOB: String, char[], java.sql.CLOB
    • BLOB: byte[], java.sql.BLOB

4.7.5 @Transient

  • 이 필드는 매핑하지 않으며, 데이터베이스에 저장, 조회 하지 않음
  • 객체에 임시로 어떤 값을 보관하고 싶을 때 사용

4.7.6 @Access

  • JPA가 엔티티 데이터에 접근하는 방식을 지정
  • @Access 사용 예
    • 필드 접근 : AccessType.FIELD, 필드 접근 권한이 private이어도 접근할 수 있다.
    • 프로퍼티 접근 : AccessType.PROPERTY, 접근자(Getter)를 사용하여 접근
    • @Access를 설정하지 않으면 @Id의 위치를 기준으로 접근 방식이 설정

실전 예제 - 데이터 중심 설계의 문제점

  • 객체 설계를 테이블 설계에 맞춘 방식
  • 테이블의 외래키를 객체에 그대로 가져옴(Order.java의 memberId는 Member.java의 정보이지만 단순 memberId만 가져옴)
  • 객체지향 설계 : 각각의 객체가 맡은 역할과 책임이 있고 관련 있는 객체끼리 참조하도록 설계해야 함
Clone this wiki locally