04. 엔티티 매핑
#
들어가며#
JPA 에서 중요하게 봐야하는 것들- 객체랑 엔티티를 어떻게 맵핑할지
- 영속성 컨텍스트
#
엔티티 매핑 소개- 객체와 테이블 매핑:
@Entity
,@Table
- 필드와 컬럼 매핑:
@Column
- 기본 키 매핑:
@Id
- 연관관계 매핑:
@ManyToOne
,@JoinColumn
- 다음 장에서 알아볼 예정
#
객체와 테이블 매핑@Entity
#
- 해당 어노테이션이 붙은 클래스는 JPA 가 관리
- JPA를 사용해서 테이블과 매핑하려면 @Entity 붙임
- 주의
- 기본 생성자 필수 (파라미터 없는 public or protected 생성자)
- 스펙상 그럼 (리플렉션등 에 필요..)
- final, enum, interface, inner 클래스 사용 X
- 저장할 필드에 final X
- 기본 생성자 필수 (파라미터 없는 public or protected 생성자)
@Table
#
- 엔티티와 매핑할 테이블 지정
- arguments
- name: 매핑할 테이블 이름이 다를 때 지정
- 나머진 뒤에서 설명
- arguments
#
DB 스키마 자동 생성- DDL을 앱 실행 시점에 자동 생성
- 운영단계에서 사용하면 안됨..
- 개발단계에서 로컬 PC에서 사용하길 권장
- 테이블 중심 -> 객체 중심 을 위해서
- DB dialect 활용해서 DB에 맞는 적절한 DDL을 생성
- 이렇게 생성된 DDL은 개발 장비에서만 사용
- 생성된 DDL은 적절히 다음은 후에 사용
@Column(unique = True, length = 10)
과 같이 필드 단위 DDL 도 가능
#
속성- persistence.xml에
<property name="hibernate.hbm2ddl.auto" value="create" />
를 설정 - create
- 시작시 drop 테이블하고 create 로 다시 만듦
- create-drop
- create와 같고 종료 시 테이블 삭제
- update
- 테이블 삭제안하고 컬럼 추가를 해줌
- 삭제는 안함
- validate
- 엔티티와 테이블이 정상 매핑되었는지 확인용
- none
- ddl 사용 안함
hivernate.hbm2ddl.auto 를 create로 설정했을 때
#
DDL 옵션 사용 시 주의사항운영장비에선 절대 create, create-drop, update 사용 XXXXXXXXX
- 개발 초기 create, update
- 테스트 서버 (update), validate (공용 개발 서버)
- 스테이징과 운영 서버는 validate, none
#
필드와 컬럼 매핑#
필드 종류@Column
#
- name: 테이블 컬럼 이름
- insertable, updatable: 등록 변경 가능 여부 (기본 TRUE)
- nullable(DDL): false면 NOT NULL 제약 조건 걸림 (기본 TRUE)
- unique(DDL): 이름이 랜덤으로 나옴, 그래서 잘 안씀
- @Table annotation으로 uniqueConstraints 옵션을 주로사함
- columnDefinition: 컬럼 정보를 직접 줄 수 있음
- length(DDL): 문자열 제한
- precision, scale(DDL): BigInteger에 주로 사용
@Enumerated
#
- value
- ORDINAL (default): enum 순서를 DB에 저장 (왜 안되는가?)
- 데이터 마이그레이션이 필요하게 되버림 (쓰지않는 것을 권장)
- STRING : enum 이름을 DB에 저장
- DB 성능이 걱정될 수 있지만 요즘 성능이 좋아 걱정안해도 됨
- ORDINAL (default): enum 순서를 DB에 저장 (왜 안되는가?)
@Temporal
#
- LocalDateTime, LocalDate 를 최신 하이버네이트 지원하기 때문에
@Temporal
을 안써도 됨
@Lob
#
- clob: 필드 타입이 String일 때
- blob: 필드 타입이 Byte일 때
@Transient
#
- 매핑안하고 앱에서 엔티티 객체에 메모리에서만 사용할 때
#
기본 키 매핑@Id
#
- 직접 할당
@GeneratedValue
#
#
AUTO- 기본값, DB 마다 상이
#
IDENTITY 전략- 기본키 생성을 DB에 위임
- 난 모르겠고 DB야 알아서 해줘~
- 대게 auto_increment
#
SEQUENCE 전략- ORACLE 에서 많이 사용
- id 타입으로 Long 을 주로 씀
- 시퀀스 이름 지정 가능
#
TABLE 전략- 키 생성 전용 테이블을 하나 만들어서 DB 시퀀스를 흉내내는 전략
- 모든 DB에 적용가능
- 성능이..
- 그래서 운영에서 쓰기 어려운 경우가 있다고 함
#
권장하는 식별자 전략- 기본 키 제약 조건
- null 아님
- 유일
- 변하면 안됨
- 미래까지 이런 자연키를 찾기 어려움
- 대리키(대체키)를 사용하자 (Auto generated value)
- 예로 주민등록번호는 기본 키로 적절하지 않음
- 권장 방법
- Long + 대체키 (Sequence, uuid) + 키 생성전략 사용
- auto_increment or sequence or uuid
#
Advanced#
IDENTITY 의 애매함- DB에 값이 생성되야 ID를 확인할 수 있음
- 영속성 컨텍스트는 ID를 몰라 1차 캐시에 저장이 어려움
- 그래서 바로 persist 시점에 insert 쿼리가 날아가고 ID를 확인할 수 있음
#
SEQUENCE 전략의 특징- 위와 마찬가지로 DB를 거쳐야 ID를 알아낼 수 있음
- insert하지 않고
call next value for MEMBER_SEQ
쿼리가 실력됨 - 마찬가지로 persist 시점에 날아가게 됨
- 성능이 좋자 않은데 라는 고민을 알 수 있음
allocationSize
가 기본이 50임... 왜?- 저장할때마다
call next
쿼리르 날려버리면 통신이 이루어져야 하므로 코스트가 듦 - DB 에 미리 allocationSize 만큼 앱에서 사용 하겠다고 하는 것임
- 여러 앱에 동시성 이슈 없이 사용 가능!?!?
#
Table 전략에서도@TableGenerator
에도 allocationSize 가 있음
#
실전 예제 - 1. 요구사항 분석과 기본 매핑#
요구사항- 회원은 상품을 주문할 수 있음
- 주문 시 여러 종류의 상품을 선택할 수 있음
#
도멘 모델 분석- 회원 : 주문 = 1 : n
- 주문 : 주문상품 = 1 : n
- 주문상품: 상품(물품) = n : 1
#
Table- Member
- id
- name
- city
- street
- zipcode
- Order
- id
- memberId (FK)
- orderDate
- status
- OrderItem
- id
- orderId (FK)
- itemId (FK)
- orderPrice
- count
- Item
- id
- name
- price
- stockQuantity
#
데이터 중심 설계의 문제점- 현재 방식은 객체 설계를 테이블 설계에 맞춘 방식
- 테이블의 외래키를 객체에 그대로 가져옴
- 객체 그래프 탐색이 불가능
- 참조가 없음
#
느낀점@Table
@Column
에 제약사항을 클래스에 명시하여 DB를 직접 보지 않더라도 코드에서 바로 볼 수 있도록 구성하는 점이 좋음- spring boot 에서 기본적으로 Entity 필드들을 order_date (스네이크 케이스) 로 변환하여 매핑하는게 기본 값임. 그리고 바꿀 수 있음
@Enumerated
의EnumType.ORDINAL
은 지양 -> 수정시 오류의 원인이 될 수 있음