본문 바로가기

Database/JPA

[JPA] 테이블과 매핑할 클래스 어노테이션

반응형

 

package jpabook.start;

import javax.persistence.*;  // JPA 어노테이션의 패키지

@Table(name="MEMBER", uniqueConstraints = {@UniqueConstraint(
        name = "NAME_AGE_UNIQUE",
        columnNames = {"NAME", "AGE"} )})
@Entity
public class Member {

    @Id
    @Column(name = "ID")
    private String id;

    @Column(name = "NAME", nullable = false, length = 10)
    private String username;

    private Integer age;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

 

@Entity 

해당 클래스를 테이블과 매핑한다고 JPA에 알려주는 어노테이션

“ 해당 클래스는 엔티티 클래스 입니다 !! “

 

@Table(name="MEMBER", 
               uniqueConstraints = {
              @UniqueConstraint(name = "NAME_AGE_UNIQUE", columnNames = {"NAME", "AGE"} )})

엔티티 클래스에 매핑할 테이블 정보를 알려주는 어노테이션

여기서는 name속성을 사용해 Member 엔티티를 Memeber 테이블에 매핑했다.

⇢ 이 어노테이션을 생략하면 클래스 이름을 테이블 이름으로 매핑한다.

- uniqueConstraints 속성은 유니크 제약 조건을 설정한다.

 

@Id

엔티티 클래스의 필드를 테이블의 기본 키에 매핑하는 어노테이션

“ 이 필드는 식별자 필드 입니다 !! “

 

* 기본키(Primary Key) 직접 할당: 기본 키를 애플리케이션에서 직접 할당, @Id 만 사용

* 기본키(Primary Key) 자동 생성: 대리 키 사용 방식, 데이터베이스의 종류에 따라 자동 생성 전략을 사용, @Id 및 @GeneratedValue 사용

전략 방법 내용 예시
AUTO - @GeneratedValue의 기본값은 AUTO
- AUTO를 사용할때 SEQUENCE나 TABLE 전략이 선택되면 시퀀스나 키 생성용 테이블을 미리 만들어둬야함.
스키마 자동 생성 기능을 사용하면 하이버네이트가 기본값을 사용해 적절한 시퀀스나 키 생성용 테이블을 만들어줄 것임
- 데이터베이스를 변경해도 코드를 수정할 필요가 없음
public class Member {
 @Id
 @GeneratedValue
 private Long id;
}
IDENTITY - 기본 키 생성을 데이터베이스에 위임
- 엔티티를 데이터베이스에 저장한 후에 식별자를 조회해 엔티티의 식별자에 할당
- em.persist()를 호출하는 즉시 INSERT SQL이 데이터베이스 전달되고, 트랜잭션 지원하는 쓰기 지연이 동작하지 않음

- 주로 MySQL, PostgreSQL, SQL Server, DB2에서 사용
public class Member {
 @Id
 @GeneratedValue(strategy=GenerationType.IDENTITY)
 private Long id;
}
SEQUENCE - 유일한 값을 순서대로 생성하는 특별할 데이터베이스 오브젝트(=데이터베이스 시퀀스)를 사용해서 기본키를 할당
- em.persist()를 호출할 때 데이터베이스 시퀀스를 사용해서 식별자를 조회, 조회한 식별자를 엔티티에 할당해 영속성 컨텍스에 엔티티 저장, 이후 트랜잭션 커밋이 되면 플러시가 일어나 엔티티를 데이터베이스에 저장.
- 주로 Oracle, PstgreSQL, DB2 H2에서 사용
public class Member {
 @Id

 @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQ_GENERATOR")
 private Long id;
혹은
 @Id
 @GeneratedValue(strategy=GenerationType.SEQUENCE)
 @SequenceGenerator(..)
 private Long id;
}
TABLE - 키 생성 전용 테이블을 생성하고 여기에 이름과 값으로 사용할 컬럼을 만들어 데이터베이스 시퀀스를 흉내내는 전략
- 시퀀스 대신에 테이블을 사용한다는 것(@TableGenerator 사용)만 제외하면 SEQEUENCE 전략과 내부 동작 방식이 같음
- 이는 모든 데이터베이스에서 사용
@TableGenerator (name="SEQ_GENERATOR", table="MY_SEQ", pkColumnValue="SEQ", allocationSize=1)
public class Member {
 @Id
 @GeneratedValue(strategy=GenerationType.TABLE, generator="SEQ_GENERATOR")
 private Long id;

}

 

[참고] 전략에 따른 최적화

IDENETIY
데이터를 데이터베이스에 INSERT한 후에 기본 키 값을 조회할 수 있다.
따라서 엔티티에 식별자 값을 할당하려면 JPA는 추가로 데이터베이스를 조회해야한다.
JDBC3에 추가된 Statement.getGeneratedKeys()를 사용하면 데이터를 저장하면서 동시게 생성된 기본 키 값을 얻어올 수 있고,
하이버네이트는 이 메소드를 사용해서 데이터베이스와 한 번만 통신한다.

SEQUENCE
데이터베이스 스퀀스를 통해 식별자를 조회하는 추가 작업이 필요하다. 
따라서 데이터베이스와 2번 통신한다.

<property name="hibernate.id.new_generator_mappings" value="true" /> 인 경우
(신규서비스인 경우 반드시 설정, 하이버네이트에 더 효과적이고 JPA 규격에 맞는 키 생성)

  JPA는 시퀀스에 접근하는 횟수를 줄이기 위해 @SequenceGenerator.allocationSize를 사용한다.
  즉 여기에 설정한 값만큼 한 번에 시퀀스 값을 증가시키고 나서 그만큼 메모리에 시퀀스 값을 할당한다.
  예를 들어 allocationSize 값이 50이면, 시퀀스를 한번에 50 증가시킨 다음에 1~50까지는 메모리에 식별자를 할당한다.
  그리고 51이 되면 시퀀스 값을 100으로 증가시킨 다음 51~100까지 메모리에서 식별자를 할당한다.

  이는 시퀀스 값을 선점하니 여러 JVM이 동시에 동작해도 기본 키 값이 충돌하지 않는 장점이 있으나,
  데이터베이스에 직접 접근해서 데이터를 등록할 때 시퀀스 값이 한번에 많이 증가한다는 단점이 있다.
  그래서 INSERT 성능이 중요하지 않으면 allocationSize의 값을 1로 설정하면 된다.

<property name="hibernate.id.new_generator_mappings" value="false" /> 인 경우
(default 설정, 기존하이버네이트 시스템을 유지보수를 위해 호환성을 위한 키 생성)

  과거에는 시퀀스 값을 하나씩 할당 받고 애플리케이션에서 allocationSize만큼 사용했다.
  예를 들어 allocationSize를 50으로 설정했다고 가정하면, 반환된 시퀀스 값이 1이면 애플리케이션에서 1~50까지 사용하고
  시퀀스 값이 2이면 애플리케이션에서 51~100까지 기본 키를 사용하는 방식이었다.

TABLE
값을 조회하면서 SELECT 쿼리를 사용하고 다음 값으로 증가시키기 위해 UPDATE 쿼리를 사용한다.
이는 SEQUENCE 비교해서 데이터베이스와 한 번 더 통신하는 단점이 있다.
@TableGenerator.allocationSize을 사용해 SEQUENCE 전략과 동일한 방법으로 접근 횟수를 설정하면 된다.

@Column(name = "NAME", nullable = false, length = 10)

필드를 컬럼에 매핑하는 어노테이션

⇢ 이 어노테이션을 생략하면 필드명을 사용해서 컬럼명으로 매핑한다.

    단, 대소문자를 구분하는 데이터베이스를 사용하면 name 속성을 사용해서 명시적으로 매핑해야한다.

- nullable 속성이 false인 경우, 자동 생성되는 DDL에 not null 제약 조건을 추가할 수 있다.

- length 속성은 자동 생성되는 DDL에 문자크기를 설정할 수 있다.

 

 

★ 위 어노테이션의 속성 기능들은 단지 DDL을 자동 생성할 때만 사용되고 JPA의 실행 로직에는 영향을 주지 않는다.

     그래도 이 기능을 사용하면 애플리케이션 개발자가 엔티티만 보고도 손쉽게 제약 조건을 파악할 수 있는 장점이 있다. 

 

반응형

❥ CHATI Github