테이블 매핑
참고
엔티티 매핑
JPA에서 엔티티 객체와 테이블을 매핑하는 방법을 설명한다.
@Entity
- 엔티티 객체를 만들 클래스에 필수로 붙어야 하는 애노테이션이다.
- 그래야만 영속성 컨텍스트의 관리를 받을 수 있다.
- JPA를 통해 테이블과 매핑하기 위해선 필수로 붙어야 한다.
- 기본 생성자가 필수로 있어야 한다. (public이나 protected)
- JPA에서 리플렉션, 프록싱 등의 내부 동작을 위해서 필요하다.
- final 클래스, enum 클래스, 인터페이스, inner 클래스로 만들면 안된다.
- db에 저장할 필드는 final 키워드를 붙이면 안된다.
DDL Auto
데이터 베이스 스키마를 자동으로 생성해주는 jpa의 기능이다.
- create
- 서버가 뜰 때마다, 엔티티 정보를 보고 스키마를 자동으로 생성해준다.
- 서버가 뜰 때, 기존에 있던 정보들은 걍 다 날려버리고 새로 정의한다.
- create-drop
- 서버가 뜰 때마다, 엔티티 정보를 바탕으로 스키마를 자동 생성한다.
- 서버가 죽을 때마다, 스키마를 다 날려버린다.
- update
- 서버가 뜰 때마다, 기존에 정의된 스키마와 다른 부분을 업데이트 해준다.
- validate
- 서버가 뜰 때마다, 정의된 스키마와 엔티티 정보가 정확히 매핑되었는지 확인 해준다.
- 스키마에 변화는 주지 않고, 매핑 정보가 다르면 에러가 뜬다.
- none
- 프로퍼티를 지워버리거나 아무거나 적으면 ddl auto 기능이 꺼진다
- none은 걍 관례상 쓴다고 한다.
- 그냥 아무것도 입력 안하거나 아무거나 입력해도 똑같음.
필드, 컬럼 매핑
자바의 멤버 필드와 테이블의 컬럼을 매핑하는 방법이다.
@Column
컬럼 매핑을 위한 어노테이션이다. 속성이 여러가지 있지만, 제약조건을 걸어주는 속성들은 ddl 날릴 때 반영이 된다. ddl-auto 안하고 직접 테이블 만들어놓고 어 이거 왜 null 제약조건 안걸려 이러면 안댐.
- name
- 매핑되는 테이블의 이름을 정해줄 수 있다.
- length, unique
- 길이나 유니크 제약조건을 걸어줄 수 있다.
- insertable, updatable
- 등록, 수정 가능 여부를 정해줄 수 있다.
- nullable
- false를 주면 not null 제약조건을 걸어준다.
- columnDefinition
- 직접 칼럼 정보를 기입해줄 수 있다.
- “varchar(20) not null” 이렇게
@Enumerated
자바의 이넘 타입을 매핑하기 위한 어노테이션이다.
- EnumType.ORDINAL
- 얘가 디폴트다.
- 숫자로 표현함. 이넘 타입의 순서가 A, B, C 있다고 하면 차례대로 1 2 3 이렇게 디비에 담아버림.
- EnumType.STRING
- 대부분의 경우에 얘를 쓰면 된다.
- 숫자로 표현했다가 이넘 클래스의 순서를 바꾼다거나 뭘 추가한다거나 하면 대참사가 일어난다.
@Temporal
시간과 관련된 타입을 매핑하기 위한 어노테이션이다.
- TemporalType.DATE
- 날짜만
- TemporalType.TIME
- 시간만
- TemporalType.TIMESTAMP
- 날짜와 시간
근데 이거는 이제 jdk8 이상 + 최신 하이버네이트 버전을 사용하면 안써도 된다.
- LocalDate, ZonedDate
- LocalDateTime, ZonedDateTime
이 타입의 애들을 쓰면 알아서 맞춰줌
@Lob
CLob BLob 같은 큰 데이터를 넣는 컬럼을 매핑하기 위한 어노테이션이다.
- CLOB
- String, char[]
- BLOB
- byte[]
어노테이션이 붙은 멤버 변수의 타입에 따라 다르게 매핑됨.
@Transient
매핑하지 않기 위한 어노테이션이다.
- 이거 붙여두면 그 필드는 걍 애플리케이션의 메모리에서만 사용하고 디비에 저장되진 않는다.
기본 키 매핑
@Id
pk를 직접 할당할 때 붙여준다.
@GeneratedValue
기본 키의 값을 숫자로 쓸 때 자동으로 생성해준다. strategy 속성으로 자동 생성 방식을 설정해줄 수 있다.
- GenerationType.IDENTITY
- 사용하는 데이터베이스에 위임한다.
- 얘는 조금 복잡하다.
- 보통 jpa는 한 트랜잭션이 커밋되는 시점에 쿼리들을 모아서 우다다 디비에 쏜다.
- 얘로 설정된 엔티티의 insert문이 있다면 즉시 디비에 쿼리를 날린다.
- 앞에서 설명했듯이 엔티티는 id 값이 필수이고, IDENTITY 전략을 사용하면 디비한테 아이디 값을 받아와야 하기 때문이다. 1. IDENTITY 전략을 사용하는 A 엔티티가 있다. 2. 트랜잭션이 아직 커밋되지 않았지만, A의 insert문이 있네? 3. 그럼 얘 먼저 처리하고 와야지 A 엔티티를 온전히 사용 가능 4. 쿼리를 날리면 디비가 아이디를 정해주고 그걸 보고 A의 아이디 값이 결정된다.
- GenerationType.AUTO
- 예가 디폴트임.
- 사용하는 데이터베이스에 맞춰서 자동으로 생성한다.
- IDENTITY랑 뭐가 다름?
- IDENTITY는 디비한테 물어보고 오는 거지만
- AUTO는 디비 뭐 쓰는지 보고 추측해서 만듦
- 그래서 insert문 만났다고 트랜잭션 안 끝났는데 지 혼자 쿼리 날리지 않음
- GenerationType.SEQUENCE
- 1부터 순서대로 차곡차곡 유니크한 값을 만들어준다.
- 따로 설정없이 사용하면 hibernate_sequence를 만들어 테이블 구분 없이 전체를 얘로 사용한다.
- @SequenceGenerator 어노테이션을 사용해서 테이블에 따로 시퀀스를 만들어 줄 수 있다.
- name, sequenceName, initialValue, allocationSize 등의 속성 값을 줄 수 있다.
- 순서대로 제너레이터 이름, 시퀀스 이름, 시퀀스 시작 값이다.
- 이 중에 allocationSize는 디폴트가 50인데, 그것은 성능을 위한 것이다.
- hibernate_sequence도 결국 디비가 관리를 하는데, Id 값을 가져올 때마다 디비한테 물어보면 성능적으로 손해를 있을 수 밖에 없다.
- 그래서 한 번에 디비의 시퀀스에는 50개를 늘려놓고, 메모리에서 50까지 카운트를 할 때 까지 다음 시퀀스 값을 물어보려고 디비한테 접근하는 걸 1/50으로 줄여준다.
- GenerationType.TABLE
- sequence 전용 테이블을 만들어서 그 테이블을 통해서 다음 값들을 참조한다.
- 따로 설정없이 사용하면 Hibernate_sequences 테이블을 만들어서 사용한다.
- @TableGenerator 어노테이션을 사용해서 시퀀스 관리용 테이블을 만들어 줄 수가 있다.
- name, tableName, pkColumnValue, allocationSize 등의 속성을 가진다.
- 순서대로 제너레이터 이름, 시퀀스 테이블 이름, pk 컬럼 이름이다.
- allocationSize는 Sequence Generator와 동일하다.
권장하는 pk 조건은 다음과 같다.
- Long type + 대체키 + @GeneratedValue
- Integer 타입보다 Long 타입의 키를 사용한다.
- 만약 Integer 타입으로 서비스를 운영하다가 키가 부족하다면,
- 다시 Long 타입으로 변경하는 작업이 훨씬 복잡해질 것이기 때문에.
- 자연키(실제 존재하는 어떤 값)보다 대체키(테이블의 데이터와 상관없는 식별을 위한 값)을 사용한다.
- 서비스 운영 중에 예기치 못한 데이터의 변경이 있을 수 있다.
- 예를 들어, 사용하면 안된다거나 등의 사유
- 그럴 때 키 값을 변경해야하는 낭패를 맞을 수 있다.
This post is licensed under CC BY 4.0 by the author.