1. @Entity
•
JPA를 사용해서 테이블과 매핑할 클래스는 @Entity 어노테이션을 필수로 붙여야 한다.
•
@Entity가 붙은 클래스는 JPA가 관리하는 것으로, 엔티티라 부른다.
1.2. @Entity 적용시 주의사항
•
기본 생성자는 필수다. (NoArgsConstructor)
•
fianl, enum, interface, inner 클래스에는 사용할 수 없다.
•
저장할 필드에 final을 사용하면 안 된다.
2. @Table
•
@Table은 엔티티와 매핑할 테이블을 지정한다.
◦
생략시 엔티티 이름을 테이블 이름으로 사용한다.
3. 데이터베이스 스키마 자동 생성
•
JPA는 데이터베이스 스키마를 자동으로 생성하는 기능을 지원한다.
•
클래스의 매핑정보를 보명 너떤 테이블에 어떤 컬럼을 사용하는지 알 수 있다.
•
JPA는 이 정보와 데이터베이스 방언을 사용해 스키마를 생성한다.
<property name="hibernate.hbm2ddl.auto" value="create" />
XML
복사
스키마 생성 허용 옵션
•
자바는 일반적으로 카멜 표기법을 사용하고 데이터베이스는 언더스코어 표기법을 사용하는데 데이터베이스 네이밍 전략 또한 변경할 수 있다.
<property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy" />
XML
복사
4. DDL 생성 기능
•
회원 이름이 필수로 입력되어야 하고, 10자를 초과하면 안 된다는 제약조건이 추가된다면 아래와 같이 @Column의 옵션을 수정해야 한다.
@Entity
@Table(name="MEMBER")
public class Member {
@Id
@Column(name = "ID")
private String id;
@Column(name = "NAME", nullable = false, length = 10) //추가
private String username;
...
}
Java
복사
•
테이블에 유니크 제약조건을 걸어야 한다면 @Table의 uniqueConstraints 속성을 사용하면 된다.
@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")
private String username;
private String age;
...
}
Java
복사
5. 기본 키 매핑
•
JPA가 제공하는 데이터베이스 기본 키 생성 전략
◦
직접 할당 = 기본 키를 애플리케이션에서 직접 할당한다.
◦
자동 생성 = 대리 키 사용 방식
▪
IDENTITY = 키본 키 생성을 데이터베이스에 위임
▪
SEQUENCE = 데이터베이스 시퀀스를 사용해 기본 키를 할당
▪
TABLE = 키 생성 테이블을 사용
•
자동 전략이 다양한 이유는 데이터베이스 벤더마다 지원하는 방식이 다르기 때문이다.
◦
SEQUENCE나 IDENTITY는 데이터베이스에 의존한다.
•
키 생성 전략을 사용하려면 속성 추가가 반드시 필요하다.
◦
하이버네이트는 하위호환을 위해 기본 값을 false로 두었다.
◦
이 옵션을 키면 키 생성 성능을 최적화하는 allocationSize 속성을 사용하는 방식이 달라진다.
<property name="hibernate.id.new_generator_mappings" value="true" />
XML
복사
5.1. 기본 키 직접 할당 전략
•
기본 키를 직접 할당하려면 다음 코드와 같이 @Id로 매핑하면 된다.
@Id
@Column(name = "id")
private String id;
Java
복사
•
@Id적용 가능 자바 타입은 다음과 같다.
◦
자바 기본형
◦
자바 래퍼(Wrapper)형
◦
String
◦
java.util.Date
◦
java.sql.Date
◦
java.math.BigDecimal
◦
java.math.BigInteger
•
기본 키 직접 할당 전략은 em.persist()로 엔티티를 저장하기 전 애플리케이션에서 직접 할당해야 한다.
◦
기본 키 직접 할당 전략에서 식별자 값 없이 저장하면 예외가 발생하는데 어떤 예외가 발생하는지 JPA 표준에는 정의되어 있지 않다.
▪
구현체로 사용하면 javax.persistence.PersistenceExption이 발생
Board board = new Board();
board.setId("id1"); //기본 키 직접 할당
em.persist(board);
Java
복사
5.2. IDENTITY 전략
•
IDENTITY는 기본 키 생성을 데이터베이스에 위임하는 전략이다.
◦
주로 MySQL, PostgreSQL, SQL Server, DB2에서 사용한다.
CREATE TABLE BOARD {
ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
DATA VARCHAR(255)
};
INSERT INTO BOARD(DATA) VALUES('A');
INSERT INTO BOARD(DATA) VALUES('B');
SQL
복사
•
테이블을 생성할 때 기본 키 컬럼인 ID에 AUTO_INCREMENT를 추가함
•
개발자가 엔티티에 직접 식별자를 할당하면 @Id 어노테이션만 있으면 된다.
◦
하지만 지금처럼 식별자가 생성되는 경우 @GeneratedValue 어노테이션을 사용하고 식별자 생성 전략을 선택해야 한다.
@Entity
public class Board {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
...
}
Java
복사
5.3. SEQUENCE 전략
•
데이터베이스 시퀀스는 유일한 값을 순서대로 생성하는 특별한 데이터베이스 오브젝트다.
•
SEQUENCE 전략은 이 시퀀스를 사용해 키본키를 생성한다.
◦
주로 오라클, PostgreSQL, DB2, H2 데이터베이스에서 사용할 수 있다.
CREATE TABLE BOARD (
ID BIGINT NOT NULL PRIMARY KEY,
DATA VARCHAR(255)
)
//시퀀스 생성
CREATE SEQUENCE BOARD_SEQ START WITH 1 INCREMENT BY 1;
SQL
복사
시퀀스 DDL
@Entity
@SequenceGenerator(
name = "BOARD_SEQ_GENERATOR",
sequenceName = "BOARD_SEQ",
initialValue = 1, allocationSize = 1)
public class Board {
@Id
@GeneraedValue(strategy = GenerationType.SEQUNCE, generator = "BOARD_SEQ_GENERATOR")
private Long id;
...
}
Java
복사
시퀀스 매핑 코드
•
@SequenceGenerator를 사용해 BOARD_SEQ_GENERATOR라는 시퀀스 생성기를 등록했다.
•
@Id이제부터 식별자 값은 BOARD_SEQ_GENERATOR시퀀스 생성기가 할당한다.
private static void logic(EntityManager em) {
Board board = new Board();
em.persist(board);
System.out.println("board.id = " + board.getId());
}
Java
복사
시퀀스 사용 코드
•
IDENTITY 전략과 같지만 내부 동작 방식은 다르다.
•
SEQUENCE 전략은 em.persist()를 호출할 때 먼저 데이터베이스 시퀀스를 사용해 식별자를 조회한다.
•
그리고 조회한 식별자를 엔티티에 할당한 후에 엔티티를 영속성 컨텍스트에 저장한다.
•
이후 트랜잭션을 커밋해 플러시가 일어나며 데이터베이스에 저장한다.
5.3.1. 주의점
•
SequenceGenerator.allocationSize 기본값이 50이다.
•
데이터베이스 시퀀스 값이 하나씩 증가하도록 설정되어 있으면 이 값을 반드시 1로 설정해야 한다.
5.4. TABLE 전략
•
TABLE 전략은 키 생성 저용 테이블을 하나 만들고 여기에 이름과 값으로 사용할 컬럼을 만들어 데이터베이스 시퀀스를 흉내내는 전략
create table MY_SEQUENCES (
sequence_name varchar(255) not null,
next_val bigint,
primary key (sequence_name)
)
SQL
복사
TABLE 전략 생성 DDL
@Entity
@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")
private Long id;
}
Java
복사
TABLE 전략 매핑 코드
private static void logic(EntityManger em) {
Board board = new Board();
em.persist(board);
System.out.println("board.id = " + board.getId());
}
Java
복사
TABLE 전략 매핑 사용 코드
•
TABLE 전략은 시퀀스 대신 테이블을 사용한다는 것만 제외하면 SEQUENCE 전략과 내부 동작 방식이 같다.
•
키를 생성할 때마다 next_val 컬럼 값이 증가한다.
•
MY_SEQUENCES 테이블에 값이 없으면 JPA가 값을 INSERT하면서 초기화하므로 값을 미리 넣어둘 필요는 없다.
5.4.1. TABLE 전략과 최적화
•
TABLE 전략은 값을 조회하며 SELECT 쿼리를 사용하고 다음 값으로 증가시키기 위해 UPDATE 쿼리를 사용한다.
•
SEQUENCE전략과는 다르게 통신 수가 한번 더 늘어난다.
•
@TableGenerator.allocationSize를 사용하여 최적화 할 수 있다.
5.5. AUTO 전략
•
데이터베이스의 종류도 많고 기본 키를 만드는 방법도 다양하다.
•
AUTO 전략은 방언에 따라 IDENTITY, SEQUENCE, TABLE 전략 중 하나를 자동으로 선택한다.
◦
@GeneratedValue.strategy의 기본 값은 AUTO다.
•
AUTO를 사용할 때 SEQUENCE나 TABLE전략이 선택되면 시퀀스나 키 생성용 테이블을 미리 만들어 두어야 한다.
◦
스키마 자동 생성을 사용하면 자동으로 만들어준다.
5.6. 기본 키 매핑 정리
•
영속성 컨텍스트는 엔티티를 식별자 값으로 구분하므로 엔티티를 영속 상태로 만들려면 식별자 값이 반드시 있어야 한다.
5.6.1. 권장하는 식별자 선택 전략
•
데이터베이스 기본 키는 다음 3가지 조건을 모두 만족해야 함
◦
null 값은 허용하지 않는다.
◦
유일해야한다.
◦
변해선 안 된다.
•
테이블의 기본 키를 선택하는 전략은 크게 2가지가 있다.
◦
자연 키 = 비즈니스에 의미가 있는 키
▪
주민등록번호, 이메일, 전화번호
◦
대리 키 = 비즈니스와 관련 없는 임의로 만들어진 키, 대체 키로도 불림
▪
오라클 시퀀스, 키생성 테이블 사용
•
자연키보다는 대리키를 권장한다.
◦
현실과 비즈니스 규칙은 생각보다 쉽게 변하기 때문이다.
◦
즉 통제할 수 없는것에 의지하지 말아야한다.
•
JPA는 모든 엔티티에 일관된 방식으로 대리 키 사용을 권장한다.
◦
테이블은 한번 정의하면 바꾸기가 어렵다.
◦
외부 풍파에 쉽게 흔들리지 않는 대리 키가 일반적으로 좋은 선택이다.
6. 필드와 컬럼 매핑: 레퍼런스
6.1. @Column
•
@Column은 객체 필드를 테이블 컬럼에 매핑한다.
•
가장 많이 사용되고 기능도 많다.
•
생략시 속성의 기본 값이 적용되며 자바의 기본타입을 이용할 경우 nullable 값이 false가 된다.
6.2. @Enumerated
•
Enum 타입을 매핑할 때 사용한다.
속성 | 기능 | 기본 값 |
value | - EnumType.ORDINAL: enum 순서를 데이터베이스에 저장
- EnumType.STRING: enum 이름을 데이터베이스에 저장 | EnumType.ORDINAL |
•
ORDINAL의 장단점
◦
데이터베이스에 저장되는 데이터 크기가 작다.
◦
이미 저장된 enum의 순서를 변경할 수 없다.
•
STRING의 장단점
◦
저장된 enum의 순서가 바뀌거나 enum이 추가되어도 안전하다.
◦
데이터베이스 저장되는 크기가 크다.
•
되도록 STRING을 사용하도록 하자.
6.3. @Temporal
•
날짜 타입을 매핑할 때 사용한다.
6.4. @Lob
•
데이터베이스 BLOB, CLOB 타입과 매핑한다.
6.4.1. 속성 정리
•
@Lob은 지정 가능한 속성이 없지만 매핑하는 필드타입에 따라 자동 매핑된다.
•
CLOB : String, char[], java.sql.CLOB
•
BLOB : byte[], java.sql.BLOB
6.4.2. 사용 예
// 매핑 코드
@Lob
private String lobString;
@Lob
private byte[] lobByte;
/*
// 오라클
lobString clob,
lobByte blob,
// MySQL
lobString longtext,
lobByte longblob,
// PostgreSQL
lobString text,
lobByte oid,
*/
Java
복사
6.5. @Transient
•
이 필드는 매핑하지 않는다.
◦
조회도 저장도 하지 않기 때문에 객체에 임시로 어떤 값을 보관하고 싶을 때 쓴다.
6.6. @Access
•
JPA가 엔티티 데이터에 접근하는 방식을 지정한다.
•
필드 접근
◦
AccessType.FIELD로 지정한다.
◦
필드에 직접 접근하며 private 제한자여도 접근 가능하다.
•
프로퍼티 접근
◦
AccessType.PROPERTY로 지정한다.
◦
접근자(Getter)를 사용한다.