엔티티 매핑
업데이트:
JPA를 사용하는데 가장 중요한 일은 엔티티와 테이블을 정확히 매핑하는 것이다. JPA는 다양한 매핑 어노테이션을 지원하는데 크게 4가지로 분류할 수 있다.
- 객체와 테이블 매핑 : @Entity, @Table
- 기본 키 매핑 : @Id
- 필드와 컬럼 매핑 : @Column
- @ManyToOne, @JoinColumn
@Entity
JPA를 사용해서 테이블과 매핑할 클래스는 필수로 붙어야 한다. @Entity가 붙은 클래스는 JPA가 관리하는 것으로, 엔티티라고 부란다.
속성
- name
- JPA에서 사용할 엔티티 이름을 지정한다. 보통 기본값인 클래스 이름을 사용한다.
- 만약 다른 패키지에 이름이 같은 엔티티 클래스가 있다면 이름 지정시 충될하지 않도록 해야 한다.
적용 주의사항
- 기본 생성자 필수다.(파라미터가 없는 public, protected 생성자)
- 자바는 생성자가 없으면 자동으로 만들지만 임이의 생성자가 있는 경우 직접 만들어 줘야 한다.
- final 클래스, enum, interface inner 클래스는 사용할 수 없다.
- 저장할 필드에 final을 사용하면 안된다.
@Table
엔티티와 매핑할 테이블을 지정한다. 생략하면 매핑한 엔티티 이름을 테이블 이름으로 사용한다.
속성
- name : 매핑할 테이블 이름
- catalog : catalog 기능이 있는 데이터베이스에서 catalog를 매핑한다.
- schema : schema 기능이 있는 데이터 베이스에서 schema를 매핑한다.
- uniqueConstraints : DDL 생성 시에 유니크 제약 조건을 만든다.
다양한 매핑 사용
@Enumerated
- enum을 사용해서 데이터를 입력할때는 @Enumerated 어노테이션으로 매핑해야 한다.
- 테이블에 데이터 저장시 enum값(0,1,2)와 변수명 값이 그대로 저장할 수 있는 방법이 있다.
- enum 숫자값으로 저장하는 경우 필드 순서가 변경될경우 기존데이터와 값이 달라져 문제가 생길 수 있다.
- 되도록이면 @Enurnerated (EnumType.STRING) 로 지정하여 변수값 그대로 저장해야 한다.
@Temporal
- 자바의 날짜 타입은 @Temporal 사용해서 매핑한다.
- 시분초가 있는지 없는지에 따라 @Temporal(TemporalType.TIMESTAMP), @Temporal(TemporalType.Date), @Temporal(TemporalType.Date) 구분해서 사용한다.
- 자바8 이후에는 LocalDatetime, LocalDate가 나눠져 있어 따로 설정 없이 구분이 가능하다
@Lob
- 설명하는 컬럼은 길이 제한이 없다. 따라서 데이터베이스 타입이 CLOB으로 지정해야 한다.
- @Lob을 사용하면 CLOB,BLOB 타입을 매핑할 수 있다.
데이터베이스 스키마 자동 생성
JPA는 데이터베이스 스키마를 자동으로 생성하는 기능을 지원한다. 클래스 매핑 정보를 보면 어떤 테이블에 어떤 컬럼으로 사용하는지 알 수 있다. JPA는 이 매핑정보와 데이터베이스 방언을 사용해서 데이터베이스 스키마를 생성한다.
설정
- persistence.xml에 <property name=”hibernate.hbm2ddl.auto” value=”“create”> 속성 추가
- 속성을 추가하면 애플리케이션 실행 시점에 데이터베이스 테이블을 자동으로 생성한다.
- hibernate.show_sql 속성을 true로 설정하면 콘솔에 실행되는 테이블 생성 DDL을 출력할 수 있다.
스키마 자동 생성 기능을 사용하면 직접 테이블을 만드느 수고를 덜수는 있따 하지만 운영 환경에서 상요할 만큼 완벽하지 않아 매핑을 어떻게 해야 하는지 참고 정도로만 사용하는 것이 좋다.
속성
- create : 기존 테이블을 삭제하고 생성한다. DROP + CREATE
- create-drop : create속성에 애플리케이션을 종료할때 생성한 DDL을 제거한다. DROP + CREATE + DROP
- update : 데이터베이스 테이블과 엔티티 매핑정보를 비교해서 변경 사항만 수정한다.
- validate : 데이터베이스 테이블과 엔티티 매핑 정보를 비교해서 차이가 있으면 경고를 남기고 실행하지 않는다
- none : 자동생성 기능을 사용하지 않으려면 속성 자체를 삭제하거나 유효하지 않는 값을 준다.(none은 유효하지 않은 값이다.)
DDL 생성 기능
- 제약조건이 추가되었을떄 DDL에 이 제약조건을 추가할 수 있다.
@Entity
@Table(name="MEMBER")
public class Member{
@Id
@Column(name="ID")
private String id;
@Column(name="NAME", nullable=false, length=10)
private String username;
}
이런 기능들은 단지 DDL을 자동으로 생성할 때만 사용되고 JPA의 실행 로직에는 영향을 주지 않는다.
기본 키 매핑
기본 키를 @Id 어노테이션을통해 애플리케이션에서 직접할당하는 데신 데이터베이스가 생성해주는 값을 사용할 수 있다. (오라클의 시퀀스 오브젝트,AUTO_INCREMENT 기능 등..)
기본 키 생성 전략
- 직접 할당 : 기본 키를 애플리케이션에서 직접 할당
- 자동 생성 : 대리 키 사용 방식
- IDENTITY : 기본 키 생성을 데이터베이스에 위임한다.
- SEQUENCE : 데이터베이스 시퀸스를 사용해서 기본 키를 할당한다.
- TABLE : 키 생성 테이블을 사용한다.
자동 생성 전략이 다양한 이유는 데이터베이스 벤더마다 지원 하는 방식이 다르기 떄문이다.
기본 키 직접 할당 전략
- @Id로 매핑하여 사용한다.
- @Id 적용 가능 자바 타입
- 자바 기본형
- 자바 래퍼 형
- String
- java.util.Date
- java.sql.Date
- java.math.BigDecimal
- java.math.BigInteger
- em.persist()로 엔티티를 저장하기 전에 애플리케이션에서 기본 키를 직접 할당하는 방법이다.
@Id
@Column(name="id")
private String id;
Board board = new Board();
board.setId("id1"); // 기본 키 직접 할당
em.persist(board);
IDENTITY 전략
- 기본 키 생성을 데이터베이스에 위임하는 전략이다.
- 주로 MySQL, PostgreSQL, SQL Server, DB2에서 사용된다.
- @GeneratedValue의 strategy 속성 값을 GenerationType.IDENTITY로 지정하면 된다.
- 데이터 베이스에 값을 저장할때 ID 컬럼을 비워두면 각 데이트베이스별 기능에 맞게 순서대로 값을 채워준다.
- ex) MySQL 컬럼에 AUTO_INCREMENT 설정되어 있으면 순서대로 채워진다.
- 이 전략을 사용하면 JPA는 기본 키 값을 얻어오기 위해 데이터베이스를 추가로 조회한다.
@Entity
public class Board{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
}
엔티티가 영속 상태가 되려면 반드시 식별자가 필요하다. IDENTITY 식별자 생성 전략은 데이터베이스에 저장해야 구할 수 있으므로 em.persist()를 호출하는 즉시 INSERT SQL이 데이터베이스에 전달되고 쓰기 지연이 동작하지 않는다.
SEQUENCE 전략
- 데이터베이스 시퀀스는 유일한 값을 순서대로 생성하는 특별한 데이터 오브젝트이다.
- 시퀀스를 지원하는 오라클, PostgreSQL, DB2, H2 데이터베이스에서 사용할 수 있다.
- 사용 코드는 IDENTITY 전략과 같지만 내부 동작 방식은 다르다.
- em.persist()를 호출할 때 먼저 데이터베이스 시퀀스를 사용해서 식별자를 조회한다.
- 조회한 식별자를 엔티티에 할당한 후에 엔티티를 영속성 컨텍스트에 저장한다.
- 이후 트랜잭션을 커밋해서 플러시가 일어나면 엔티티를 데이터베이스에 저장한다.
- @SequenceGenertor 속성
- name : 식별자 생성기 이름
- sequenceName : 데이터베이스에 동록되어 있는 시퀀스 이름
- initialValue : DDL 생성시에만 사용됨, DDL을 생설할떄 처음 시작하는 수를 지정
- allocationSize : 시퀀스 한 번 호출에 증가하는 수(성능 최적화에 사용됨)
- catalog, schema : 데이터베이스 catalog, schema 이름
@Entity
@SequenceGenerator(
name = "BOARD_SEQ_GENERATOR",
sequenceName = "BOARD_SEQ", // 매핑할 데이터베이스 시퀀스 이름
initialValue = 1, allocationSize = 1)
public class Board {
@Id
@GeneratedValue(strategy = "BOARD_SEQ_GENERATOR")
private Long id;
}
allocationSize는 지정한 수만큼 시퀀스를 증가 시키고 메모리에 식별자를 할당한다. 그리고 지정한 수가 넘어가면 다시 지정한 수만큼 증가시킨다음 메모리에 식별한다.
이 방식을 사용하면 여러 JVM이 동시에 동작해도 기본 키 값이 충돌되지 않는 장점이 있다. 반면에 데이터베이스에 접근해서 데이터를 등록할 때 시퀀스 값이 한번에 많이 증가한다는 점을 염두해 둬야 한다.
TABLE 전략
- 먼저 키생성 용도로 테이블을 만들어 사용하는 방식이다.
- 테이블을 따로 만들어 사용하기 때문에 어떠한 DB를 사용하더라고 적용이 가능하다.
- 테이블 생성시 sequence_name 컬럼을 시퀀스 이름으로 사용하고 next_val 컬럼을 시퀀스 값으로 사용한다.
import org.springframework.boot.autoconfigure.domain.EntityScan;
@Entity
@TableGenerator(
name="BOARD_SEQ_GENERATOR",
table="MY_SEQUENCES",
pkColumnValue="BOARD_SEQ", allocationSIze=1
)
댓글남기기