[JPA 프로그래밍] 3. 엔티티 매핑
객체와 테이블 매핑
@Entity
JPA를 사용해서 테이블과 매핑할 클래스는 @Entity 어노테이션을 필수로 붙여야 한다. @Entity가 붙은 클래스는 JPA가 관리하는 것으로, 엔티티라 부른다.
[주의]
- 기본 생성자는 필수다 (파라미터가 없는 public 또는 protected 생성자)
- final 클래스, enum, interface, inner 클래스에는 사용할 수 없다
- 저장할 필드에 final을 사용하면 안된다 (즉, 상수 불가능)
* 자바는 생성자가 하나도 없으면 기본 생성자를 만든다. 하지만 생성자를 하나 이상을 만들었을 경우에는 기본 생성자를 직접 만들어야 한다.
속성 | 기능 | 기본값 |
name | JPA에서 사용할 엔티티의 이름을 지정한다. 같은 클래스의 이름이 없으면 가급적 기본값을 사용한다 |
클래스 이름을 그대로 사용한다 |
@Table
@Table은 엔티티와 매핑할 테이블을 지정한다. 생략하면 매핑한 엔티티 이름을 테이블 이름으로 사용한다.
속성 | 기능 | 기본값 |
name | 매핑할 테이블 이름 | 엔티티 이름을 사용 |
catalog | 데이터베이스 catalog 매핑 | |
schema | 데이터베이스 schema 매핑 | |
uniqueConstraints (DDL) | DDL 생성 시에 유니크 제약 조건 생성 |
@Table(name = "MBR")이라고 하면 쿼리가 ... into MBR ... 으로 생성된다.
데이터베이스 스키마 자동 생성
JPA에서는 애플리케이션 실행 시점에 DDL(Data Definition Language)을 자동으로 생성한다. 설정해둔 데이터베이스 방언을 활용해서 데이터베이스에 맞는 적절한 DDL을 생성한다.
- hibernamte.hbm2dd.auto
옵션 | 설명 |
create | 기존 테이블 삭제 후 다시 생성한다. (drop + create) |
create-drop | create와 같으나 종료 시점에 테이블을 drop한다. |
update | 변경분만 반영한다. (운영 DB에서는 사용하면 안된다) |
validate | 엔티티와 테이블이 정상 매핑되었는지만 확인한다. |
none | 사용하지 않는다. |
[주의]
- 운영 장비에는 절대 create, create-drop, update를 사용하면 안된다.
- 개발 초기 단계는 create 또는 update
- 테스트 서버는 update 또는 validate
- 스테이징과 운영 서버는 validate 또는 none
DDL 생성 기능에 제약 조건을 추가할 수 있다. DDL 생성 기능은 DDL을 자동 생성할 때만 사용되고 JPA의 실행 로직에는 영향을 주지 않는다.
- 회원 이름은 필수, 10자 초과 불가
@Column(nullable = false, length = 10)
- 유니크 제약 조건 추가
@Table(uniqueConstraints={@UniqueConstraint(name="NAME_AGE_UNIQUE", columnNames={"NAME", "AGE"})})
필드와 컬럼 매핑
요구사항에 따라 객체의 필드와 테이블의 컬럼을 매핑해야 하는 경우들이 생긴다. 그 때 사용할 수 있는 어노테이션들에 대해서 알아보자
- 필드와 컬럼 매핑 분류 (hibernate.hbm2ddl.auto)
어노테이션 | 설명 |
@Column | 컬럼을 매핑한다 |
@Temporal | 날짜 타입을 매핑한다 |
@Enumerated | 자바의 enum 타입을 매핑한다 |
@Lob | BLOB, CLOB 타입을 매핑한다 |
@Transient | 특정 필드를 컬럼에 매핑하지 않는다 |
@Column
@Column은 객체 필드를 테이블 컬럼에 매핑한다.
속성 | 설명 | 기본값 |
name | 필드와 매핑할 테이블의 컬럼 이름 | 객체의 필드 이름 |
insertable, updatable | 등록, 변경 가능 여부 | true |
nullable(DDL) | null 값의 허용 여부를 설정한다. false로 설정하면 DDL 생성 시에 not null 제약 조건이 붙는다. |
|
unique(DDL) | @Table의 uniqueConstraints외 같지만 한 컬럼에 간단히 유니크 제약 조건을 걸 때 사용한다 | |
columnDefinition(DDL) | 데이터베이스 컬럼 정보를 직접 줄 수 있다 ex) varchar(100) default 'EMPTY' |
필드와 자바 타입과 방언 정보를 사용 |
length(DDL) | 문자 길이 제약 조건, String 타입에만 사용한다 | 255 |
precision, scale(DDL) | BigDecimal 타입에서 사용한다 precision은 소수점을 포함한 전체 자릿수를, scale은 소수의 자릿수다. 아주 큰 숫자나 정밀한 소수를 다루어야 할 때만 사용한다 |
precision = 19 scale = 2 |
@Enumerated
자바의 enum 타입을 매핑할 때 사용한다.
enum에 새로운 값이 추가될 경우 순서가 뒤바뀔 수 있기 때문에 ORDINAL 타입을 사용하면 안 된다.
속성 | 설명 | 기본값 |
value | - EnumType.ORDINAL : enum 순서를 데이터베이스에 저장 - EnumType.STRING : enum 이름을 데이터 베이스에 저장 |
EnumType.ORDINAL |
@Temporal
날짜 타입(java.util.Date, java.util.Calendar)을 매핑할 때 사용한다.
속성 | 설명 | 기본값 |
value | - TemporalType.DATE : 날짜, 데이터베이스 date 타입과 매핑 ex) 2025-02-02 - TemporalType.TIME : 시간, 데이터베이스 time 타입과 매핑 ex) 11:11:11 - TempoarlType.TIMESTAMP : 날짜와 시간, 데이터베이스 timestamp 타입과 매핑 ex) 2025-02-02 11:11:11 |
@Lob
데이터베이스 BLOB, CLOB 타입과 매핑한다
- @Lob에는 지정할 수 있는 속성이 없다
- 매핑하는 필드 타입이 문자면 CLOB 매핑, 나머지는 BLOB 매핑
- CLOB : String, char[], java.sql.CLOB
- BLOB : byte[], java.sql.BLOB
@Transient
데이터 베이스 컬럼과 매핑을 하지 않는다.
- 데이터베이스에 저장, 조회도 불가능하다
- 주로 메모리상에서만 임시로 어떤 값을 보관하고 싶을 때 사용한다
예시
@Entity
public class Member {
@Id
private Long id;
@Column(name = "name") // 객체에는 username, 테이블에는 name
private String username;
private Integer age;
@Enumerated(EnumType.STRING)
private RoleType roleType;
@Temporal(TemporalType.TIMESTAMP)
private Date createdDate;
@Temporal(TemporalType.TIMESTAMP)
private Date lastModifiedDate;
@Lob
private String description;
}
기본 키 매핑
권장하는 식별자 전략
키본키 제약 조건 : null 아님, 유일, 변하면 안됨
권장 : Long형 + 대체키 + 키 생성 전략 사용
직접 할당
기본키 위에 @Id 어노테이션만 붙여주면 된다. 그 이후 새로운 객체를 생성할 때 직접 id값을 설정해줘야 한다.
@Id
private String id;
자동 생성(@GeneratedValue)
@Id와 @GeneratedValue 어노테이션을 같이 쓰면 기본키를 자동 생성한다.
- IDENTITY : 데이터베이스에 위임
- SEQUENCE : 데이터베이스 시퀀스 오브젝트 사용
- TABLE : 키 생성용 테이블 사용, 모든 DB에서 사용
- AUTO : 방언에 따라 자동 지정, 기본값
1) IDENTITY 전략
기본 키 생성을 데이터베이스에 위임한다. 주로 MySQL, PostgreSQL, SQL Server, DB2에서 사용한다. 예를 들어 MySQL의 AUTO_INCREMENT 기능은 데이터베이스가 자동으로 기본 키를 생성해 준다. 아래의 DDL을 보면 id에 auto_increment로 생성됨을 알 수 있다.
JPA는 보통 트랜잭션 커밋 시점에 INSERT SQL을 실행한다. 엔티티가 영속 상태가 되려면 식별자(PK)가 반드시 필요한데, AUTO_INCREMENT를 사용하는 경우에는 데이터베이스에 INSERT_SQL을 실행한 이후에 ID 값을 알 수 있다. 그래서 IDENTITY 전략은 em.persist() 시점에 즉시 INSERT SQL을 실행하고 DB에서 식별자를 조회한다. 따라서 이 전략은 트랜잭션을 지원하는 쓰기 지원이 동작하지 않는다.
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
2) SEQUENCE 전략
데이터베이스 시퀀스는 유일한 값을 순서대로 생성하는 특별한 데이터베이스 오브젝트이다. SEQUENCE 전략은 이 시퀀스를 사용해서 기본키를 생성한다. 주로 오라클, PostgreSQL, DB2, H2 데이터베이스에서 사용한다.
- @SequenceGenerator 어노테이션을 사용하면 테이블마다 다른 시퀀스를 만들어 저장할 수 있다
- em.persist()를 하기 전, next call을 통해서 시퀀스에서 다음 기본키 값을 가져온다. IDENTITY 전략과 달리, 쓰기 지연 SQL 저장소를 사용할 수 있다.
@Entity
@SequenceGenerator(
name = “MEMBER_SEQ_GENERATOR",
sequenceName = “MEMBER_SEQ", //매핑할 데이터베이스 시퀀스 이름
initialValue = 1, allocationSize = 1)
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE,
generator = "MEMBER_SEQ_GENERATOR")
private Long id;
}
- @SequenceGenerator
속성 | 설명 | 기본값 |
name | 식별자 생성기 이름 | 필수 |
sequenceName | 데이터베이스에 등록되어 있는 시퀀스 이름 | hibernate_sequence |
initialValue | DDL 생성 시에만 사용됨. 시퀀스 DDL을 생성할 때 처음 시작하는 수를 지정한다 |
1 |
allocationSize | 시퀀스 한 번 호출에 증가하는 수 (성능 최적화에 사용됨) | 50 |
catalog, schema | 데이터베이스 catalog, schema 이름 |
allocationSize 속성은 성능 최적화를 위해 사용된다. allocationSize를 50으로 설정해두면 DB 시퀀스에서 1부터 50까지의 값을 가져와 메모리에 올려놓고 em.persist()가 호출될 때마다 메모리에서 1개씩 사용한다. 그래서 1부터 50까지는 데이터베이스를 한 번만 호출해도 사용할 수 있기 때문에 성능이 향상되는 것이다
3) TABLE 전략
키 생성 전용 테이블을 하나 만들어서 데이터베이스 시퀀스를 흉내내는 전략이다.
- 장점 : 모든 데이터베이스에 적용 가능
- 단점 : 성능
@Entity
@TableGenerator(
name = "MEMBER_SEQ_GENERATOR",
table = "MY_SEQUENCES",
pkColumnValue = “MEMBER_SEQ", allocationSize = 1)
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.TABLE,
generator = "MEMBER_SEQ_GENERATOR")
private Long id;
}
- @TableGenerator
속성 | 설명 | 기본값 |
name | 식별자 생성기 이름 | 필수 |
table | 키 생성 테이블명 | hibernate_sequence |
pkColumnName | 시퀀스 컬럼명 | sequence_name |
valueColumnNa | 시퀀스 값 컬럼명 | next_val |
pkColumnValue | 키로 사용할 값 이름 | 엔티티 이름 |
initialValue | 초기값, 마지막으로 생성된 값이 기준이다 | 0 |
allocationSize | 시퀀스 한 번 호출에 증가하는 수 (성능 최적화에 사용됨) | 50 |
catalog, schema | 데이터베이스 catalog, schema 이름 | |
uniqueConstraints(DDL) | 유니크 제약 조건을 지정할 수 있다. |