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의 실행 로직에는 영향을 주지 않는다.
그래도 이 기능을 사용하면 애플리케이션 개발자가 엔티티만 보고도 손쉽게 제약 조건을 파악할 수 있는 장점이 있다.
'Database > JPA' 카테고리의 다른 글
[JPA] 영속성 관리 : 매핑한 엔티티를 엔티티 매니저를 통해 엔티티의 생명 주기는 어떻게 사용되는가 (0) | 2020.08.10 |
---|---|
[JPA] 프로젝트에서 JPA 적용 방법 (0) | 2020.08.10 |
[JPA] 버전별 특징 (0) | 2020.08.10 |
[JPA] 데이터베이스 방언, Dialet (0) | 2020.08.10 |
[JPA] 객체와 테이블의 전격 비교 분석 (0) | 2020.08.10 |
[JPA] 그것은 무엇인가? (0) | 2020.08.06 |