[JPA] 엔티티 매핑 어노테이션
객체와 테이블 매핑: @Entity, @Table
필드와 컬럼 매핑: @Column, @Temporal, @Enumerated, @Lob, @Transient
기본 키 매핑: @Id, @GeneratedValue
연관관계 매핑: @ManyToOne,@JoinColumn
객체와 테이블 매핑
@Entity : @Entity가 붙은 클래스는 JPA가 관리하게 된다. 필수적으로 붙여줘야한다.
주의 해야하는 점은 기본 constructor가 필수적으로 있어야하고 final, enum, interface, inner class에는 사용할 수 없다. 또한 저장해야하는 필드에 final 키워드가 붙으면 역시 사용할 수 없다.
@Entity의 속성으로는 name이 있다. 이는 JPA에서 사용할 엔티티 이름을 설정한다. 이때 지정하지 않으면 default는 클래스 이름을 그대로 가져간다. 가급적이면 기본값을 이용하되, order과 같은 데이터베이스에 예약어로 되어있는 키워드는 관례에 따라 예를들어 ORDERS 이런식으로 지정해서 저장하는 것이 좋다.
필드와 컬럼 매핑
@Column : 컬럼 매핑
attribute | description | default value |
name | 필드와 매핑할 테이블의 컬럼 이름 | 필드 이름 |
insertable, updatable | 등록, 변경 가능 여부 | TRUE |
nullable | null 값의 허용 여부를 설정. false로 설정하면 DDL 생성 시에 not null 제약조건이 붙는다. | |
unique | @Table의 uniqueConstraints와 같지만 한 컬럼에 간단히 유니크 제약조건을 걸 때 사용한다. | |
columnDefinition | 데이터베이스 컬럼 정보를 직접 줄 수 있다. ex) varchar(100) default ‘EMPTY' | 필드의 자바 타입과 방언 정보를 사용해서 작성 |
length | 문자 길이 제약조건, String 타입에만 사용 가능 | 255 |
precision, scale | BigDecimal 타입에서 사용한다(BigInteger도 사용할 수 있다). precision은 소수점을 포함한 전체 자 릿수를, scale은 소수의 자릿수다. 아주 큰 숫자나 정 밀한 소수를 다루어야 할 때만 사용한다. | precision=19, scale=2 |
@Enumerated : enum 타입을 매핑할 때 사용
속성으로는 value가 있는데 EnumType.ORDINAL은 enum 순서를 데이터베이스에 저장할 때, EnumType.STRING은 enum 이름을 데이터베이스에 저장한다. 주의해야하는 점은 ORDINAL은 숫자를 저장하기 때문에 enum의 숫자로 들어가게 된다. 따라서 enum의 맨 앞에 다른 이름이 들어가는 경우 숫자가 하나씩 밀리게 되므로 데이터베이스에 저장된 값의 의미와 상이해질 수 있다. 따라서 EnumType.STRING 만 사용하자.
@Temporal : 날짜 타입(java.util.Date, java.util.Calendar)을 매핑할 때 사용
자바8의 경우에는 LocalDate와 LocalDateTime을 제공하는데 이때는 어노테이션을 매핑하지 않아도 hibernate가 알아서 처리해주지만 Date나 Calendar의 경우에는 그렇지 않기 때문에 이를 매핑해주는 어노테이션이다.
@Lob : 데이터베이스 BLOB, CLOB 타입과 매핑
기본적으로 @Lob에는 지정할 수 있는 속성이 없다. 문자냐 숫자냐에 따라서 CLOB과 BLOB으로 알아서 매핑해준다.
CLOB: String, char[], java.sql.CLOB
BLOB: byte[], java.sql. BLOB
@Transient
필드 매핑을 하지 않을 때 사용한다. 데이터베이스에 저장하지 않고, 조회도 하지 않을때 사용한다. 메모리상에서만 임시로 어떤 값을 보관하고 싶을 때 사용한다. @Transient private Integer temp;
기본 키 매핑 어노테이션
직접 키를 할당하고 싶은 경우에는 @Id만 사용하면 된다. 하지만 그렇지 않고 자동 생성을 이용하고 싶은 경우에는 @GeneratedValue를 사용한다.
IDENTITY | 데이터베이스에 위임 ex) MYSQL, PostgreSQL |
SEQUENCE | 데이터베이스 시퀀스 오브젝트 사용, ex) ORACLE 이때는 @SequenceGenerator가 필요하다. |
TABLE | 키 생성용 테이블 사용, 모든 DB에서 사용 @TableGenerator 필요하다. |
AUTO | 방언에 따라 자동 지정, 기본값 |
IDENTITY 전략 :
기본 키 생성을 데이터베이스에 위임한다. 주로 MySQL, PostgreSQL 등에서사용한다. MySQL의 AUTO_INCREMENT와 같은 것을 의미한다. JPA는 보통 트랜잭션 커밋 시점에 INSERT 쿼리를 실행하는데 AUTO_INCREMENT는 데이터베이스에 INSERT한 이후에 ID 값을 알 수 있다. 따라서 persist() 시점에 즉시 INSERT 쿼리를 실행하고 DB에서 식별자를 조회한다. 즉 버퍼링 처리해서 한번에 쿼리를 날리는 행위가 불가능하다.
@Entity
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) // DB야 알아서 해줘 이런느낌, persist()하면 바로 쿼리 날라감. 즉, 버퍼링처리해서 한번에 쿼리날리는 행위가 불가능
private Long id;
}
SEQUENCE 전략 :
데이터베이스 시퀀스는 유일한 값을 순서대로 생성하는 특별한 데이터베이스 오브젝트(예: 오라클 시퀀스)
오라클, PostgreSQL, DB2, H2 데이터베이스에서 사용한다.
@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
attribute | description | default value |
name | 식별자 생성기 이름 | 필수 |
sequenceName | 데이터베이스에 등록되어 있는 시퀀스 이름 | hibernate_sequence |
initialValue | DDL 생성 시에만 사용됨, 시퀀스 DDL을 생성할 때 처음 1 시작하는 수를 지정한다. | 1 |
allocationSize | 시퀀스 한 번 호출에 증가하는 수(성능 최적화에 사용됨 데이터베이스 시퀀스 값이 하나씩 증가하도록 설정되어 있으면 이 값 을 반드시 1로 설정해야 한다 | 50 |
catalog, schema | 데이터베이스 catalog, schema 이름 |
allocationSize는 최대 몇개까지 생성해놓고 사용할 것인지에 대한 값이다. 즉 50으로 설정해두면 persist()를 호출할 때 즉시 쿼리가 날라가는 것이 아니고, 50개까지 확보해두고 50개를 다쓰면 그때 쿼리를 날린다.
위의 표 처럼 설정했을때 동작 방식은 먼저 1개가 기본으로 사용이 가능하고 persist()가 이루어지면 1개를 사용하고 모두 사용했으므로 50개를 확보해놓는다. 즉, 51개가 모두 사용되면 다시 50개를 확보하고 영속성 컨텍스트에 집어 넣고 쓰기 지연 SQL 저장소에 집어넣고 .. commit 시점에 쿼리를 날릴 수 있기 떄문에 버퍼로 사용이 가능하다.
근데.. 김영한 선생님 말씀으로는 이게성능에 도움이 엄청 크진 않다고 하심..
TABLE 전략 :
키 생성 전용 테이블을 하나 만들어서 데이터베이스 시퀀스를 흉 내내는 전략이다. 장점은 모든 데이터베이스에 적용 가능하나, 성능 단점이다.
권장하는 식별자 전략!
기본 키 제약 조건: null 아님, 유일, 변하면 안된다. 미래까지 이 조건을 만족하는 자연키는 찾기 어렵다. 대체키를 사용하자. 예를 들어 주민등록번호도 기본 키로 적절하기 않다.
권장: Long형 + 대체키 + 키 생성전략 사용