@Entity 는 JPA를 사용해서 테이블과 매핑할 클래스를 지정하는 것이다.
JPA에서 사용할 엔티티 이름을 지정한다. name속성은 생략가능하다.
(설정하지 않으면 클래스 이름을 그대로 사용)
@Table은 엔티티와 매핑할 테이블을 지정한다.
생략한다면? 엔티티 이름을 테이블 이름으로 사용한다.
| 속성명 | 기능 | 기본값 |
|---|---|---|
| name | 매핑할 테이블 이름 | 엔티티 이름을 사용한다. |
| catalog | catalog 기능이 있는 데이터베이스에서 catalog를 매핑한다. | - |
| schema | schema 기능이 있는 데이터베이스에서 schema를 매핑한다. | - |
| uniqueConstraints(DDL) | DDL 생성시에 유니크 제약조건을 만든다. | - |
persistence.xml
<property name="hibernate.hbm2ddl.auto" value="create"/>
| 옵션 | 설명 |
|---|---|
| create | 기존 테이블을 삭제하고 새로 생성한다. (DROP+CREATE) |
| create-drop | (DROP+CREATE+DROP) |
| update | 데이터베이스 테이블과 엔티티 매핑정보를 비교해서 변경 사항만 수정한다. |
| validate | 테이블과 엔티티를 비교해서 차이가 있으면 경고를 남기고 애플리케이션을 실행하지 않는다.(DDL을 실행하지 않음) |
| none | 자동생성기능 사용하지 않음 |
자바언어는 카멜표기법을 사용하고, 데이터베이스는 언더스코어를 주로 사용한다.
@Column(name="role_type") // 언더스코어로 구분
String roleType; // 카멜 표기법으로 구분
컬럼에 일일이 name을 언더스코어를 사용하긴 귀찮으므로,
<property name="hibernate.ejb.naming_strategy"
value="org.hibernate.cfg.ImprovedNamingStrategy" />
를 설정해두면 된다.
코드를 먼저 보자.
@Entity
@Table(name = "MEMBER", uniqueConstraints = {@UniqueConstraint(
name = "NAME_AGE_UNIQUE",
columnNames = {"NAME", "AGE"}
)})
public class Member {
@Id
@Column(name = "id")
private String id;
@Column(name = "NAME", nullable = false, length = 10)
private String username;
위 조건들은 모두 DDL을 자동으로 생성할 때만 사용되고 JPA실행 로직에는 영향을 주지 않는다.
키 생성전략을 사용하려면 persisence.xml 에 hibernate.id.new_generator_mappings를 true 로 설정해줘야한다.
기본키를 직접 할당하려면 @Id로 매핑하면 된다.
@Id
@Column(name = "id")
private String id;
IDENTITY 는 기본키 생성을 데이터베이스에 위임하는 전략이다. DB의 IDENTITY컬럼을 이용하는 방식으로 데이터베이스에 의존적이다.
주로 MySQL, PostgreSQL, SQL Server, DB2 에서 사용한다.
(예. MySQL 의 AUTO_INCREMENT 기능)
@Entity
public class Board{
@Id
@GenerateValue(strategy = GenerationType.IDENTITY)
private Long id;
...
}
위 처럼 @GenerateValue어노테이션에 IDENTITY 전략을 사용한다.
여기서 해당 ID값을 읽어왔을 때,
private static void logic2(EntityManager em) {
Board board = new Board();
em.persist(board);
System.out.println("board.id = " + board.getId());
}
출력된 값은 데이터베이스가 생성한 값을 JPA가 조회한 것이다.
IDENTITY 전략은 데이터를 데이터베이스에 INSERT 한 후에 기본 키 값을 조회할 수 있다.
따라서 엔티티에 식별자 값을 할당하려면 JPA는 추가로 데이터베이스를 조회해야 한다.
INDENTITY 식별자 생성 전략은 쓰기지연이 안된다!
해당 전략은 엔티티를 저장해야 식별자를 구할 수 있으므로 em.persist()호출하는 즉시 INSERT SQL이 데이터베이스에 전달된다.
시퀀스는 유일한 값을 순서대로 생성하는 특별한 데이터베이스 오브젝트다.
이 전략은 시퀀스를 지원하는 오라클, PostgreSQL, DB2, H2 데이터베이스에서 사용할 수 있다.
SequenceGenerator 속성
| 속성명 | 기능 | 기본값 |
|---|---|---|
| name | 식별자 생성기 이름 | 필수 |
| sequenceName | 데이터베이스에 등록되어 있는 시퀀스 이름 | hibernate_sequene |
| initialValue | 시퀀스 DDL을 생성할 때 처음 시작하는 수를 지정 | 1 |
| allocationSize | 시퀀스 한 번 호출에 증가하는 수 | 50 |
| name | 식별자 생성기 이름 | 필수 |
@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")
//@SequenceGenerator를 여기에 추가해도 된다.
private Long id;
...
}
SEQUENCE 전략은 데이터베이스 시퀀스를 통해 식별자를 조회하는 추가 작업후 INSERT를 진행한다. 따라서 데이터베이스와 2번 통신한다.
그렇다면 접근을 최소화하기 위한 방법은 무엇일까??
@SequenceGenerator.allocationSize
해당 속성을 통해 최적화를 한다. 설정한 값 만큼 한 번에 시퀀스 값을 증가시키고 나서 그만큼 메모리에 시퀀스값을 할당한다.
기본값이 50이므로, 한번 50번 증가시키고, 메모리에서 식별자를 할당한다.
여러 JVM이 동시에 접근해도 기본키 값이 충돌하지 않는 장점이 있다.
만약, 시퀀스값이 한번에 많이 올라가는게 부담스럽거나, INSERT 성능이 중요하지 않다면 1로 설정하고 사용하면 된다.
테이블을 이용하여 데이터베이스 시퀀스를 흉내내는 전략이다. 모든 데이터베이스에서 사용할 수 있다.
@TableGenerator(
name = "BOARD_SEQ_GENERATOR",
table = "MY_SEQUENCES",
pkColumnValue = "BOARD_SEQ", allocationSize = 1
)
public class Board {
@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = "BOARD_SEQ_GENERATOR") // table 전략
private Long id;
...
}
코드를 보면 사용방법을 알 수 있다.
SEQUENCE 전략과 내부 동작방식이 같다.
TABLE 전략 최적화
TABLE 전략은 값을 조회하면서 SELECT 쿼리한번과 값을 증가시키는 UPDATE쿼리를 한번 더 사용한다. 즉, SEQUENCE 전략과비교해서 DB와 한 번 더 통신한다.
얘도 최적화 하기 위해서 @TableGenerator.allocationSize 를 사용하면 된다.
선택한 데이터베이스 방언에 따라 IDENTITY, SEQUENCE, TABLE 전략 중하나를 자동으로 선택한다.
자연키 : 비즈니스에 의미가 있는 키(주민등록번호, 전화번호..)
대리키 : 비즈니스와 관련 없는 임의의 키, 대체키
자연 키보다는 대리키를 권장한다. 왜냐하면 비즈니스 환경은 언젠가 변할 수 있기 때문이다.
@Column 은 객체 필드를 테이블 컬럼에 매핑한다.
속성
name : 필드와 매핑할 테이블의 컬럼 이름
nullable : null값의 허용여부를 설정, 자바 기본타입 사용시 nullable = false가 안전하다.
unique : 한 컬럼에 간단히 유니크 제약조건을 걸 때 사용
columnDefinition : 데이터베이스 컬럼 정보를 직접 줄 수 있다.
length : 문자 길이 제약조건
percision, scale : BigDecimal 타입에서 사용, precision은 소수점을 포함한 전체자리, scale은 소수의 자릿수
자바의 enum타입을 매핑할 때 사용한다.
@Enumerated(EnumType.STRING)
enum 이름을 그대로 세팅한다.(권장 설정)
@Enumerated(EnumType.ORDINAL)
enum순서를 데이터베이스에 저장한다.(Default)
날짜타입을 매핑할 때 사용한다. @Temporal 생략시 timestamp 로 설정된다.
@Temporal(TemporalType.DATE)
데이터베이스 date타입과 매핑(ex 2013-10-17)
@Temporal(TemporalType.TIME)
데이터베이스 time타입과 매핑(ex 22:10:00)
@Temporal(TemporalType.TIMESTAMP)
데이터베이스 timestamp와 매핑(ex 2013-10-17 22:10:00)
데이터베이스 BLOB, CLOB 타입과 매핑한다.(외부 바이너리 파일, 큰데이터를 외부파일로 저장하는 용도)
이 필드는 매핑하지 않는다.
JPA가 엔티티 데이터에 접근하는 방식을 지정한다.