일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- Design Pattern
- 카프카
- Java
- 푸시
- 웹사이트최적화기법
- 웹사이트성능
- ddd
- php
- kafka
- nginx설치
- GCM 번역
- Push
- 도메인 주도 개발
- 디자인패턴
- GCM
- notification
- nginx
- nginx설정
- 카프카 트랜잭션
- git
- 성능
- graphql
- gcm 푸시 번역
- JPA
- 푸시 번역
- APNS
- 웹사이트 성능
- 자바스크립트
- 페이스북 번역
- Today
- Total
간단한 개발관련 내용
4장 엔터티 매핑 본문
4.1 @Entity
- 기본생성자는 필수다
- 파라미터가 없는 public 또는 protected 생성자로 선언.
- private은 JPA가 접근할 수 없기 때문에 안된다
- final 클래스, enum, interface, inner 클래스에는 사용할 수 없다
- 저장할 필드에 final을 사용하면 안된다
<aside> 💡
JPA는 리플렉션을 사용하여 데이터베이스에서 조회된 데이터를 기반으로 객체를 생성합니다. 리플렉션으로 객체를 생성할 때는 매개변수가 없는 생성자를 호출할 수밖에 없습니다. 따라서 파라미터가 없는 생성자가 없으면 JPA는 해당 엔티티 클래스를 인스턴스화할 수 없습니다.
</aside>
4.2 @Table
- name
- catalog
- schema
- uniqueConstraints
4.3 다양한 매핑사용
- @Enumerated : java enum
- @Temporal : java date
- @Lob : CLOB, BLOB
4.4 데이터베이스 스키마 자동 생성
- create : DROP + CREATE
- create-drop : : DROP + CREATE + DROP
- 애플리케이션을 종료할 때 DROP
- update : DB와 엔터티 비교 후 변경사항만 저장
- validate : DB와 엔터티 비교 후 차이가 있으면 경고하고 애플리케이션 실행하지 않음.
- none
<aside> 💡
이름 매핑 전략 변경하기
단어와 단어를 구분할 때 자바 언어는 관계상 roleType과 같이 카멜표기법을 주로 사용하고, 데이터베이스는 관례상 role_type과 같이 언더스코어를 주로 사용한다.
hibernate.ejb.naming_strategy 속성을 사용하면 이름 매핑 전략을 변경할 수 있다. ImprovedNamingStrategy 클래스를 사용해서 테이블 명이나 컬럼 명이 생략되면 자바의 카멜 표기법을 테이블의 언더스코어 표기법으로 매핑한다.
</aside>
4.5 DDL 생성기능
- @Column 의 notnull, length 속성
- @Table의 uniqueConstraints 속성
- DDL을 자동 생성할 때만 사용되고 JPA의 실행 로직에는 영향을 주지 않는다
4.6 기본 키 매핑
- 직접할당
- 기본키를 애플리케이션에서 직접 할당한다
- 자동생성
- 대리키 이용방식
- IDENTITY : 기본 키 생성을 데이터베이스에 위임
- SEQUENCE : 데이터베이스 시퀀스
- TABLE : 키 생성 테이블을 이용
- 대리키 이용방식
- @Id
- 기본키를 직접 할당하려면 @Id만 사용하면 되고,
- 자동 생성 전략을 사용하려면 @Id에 @GeneratedValue를 추가하고 원하는 키 생성전략을 선택하면 된다.
4.6.1 기본 키 직접 할당 전략
- 자바 기본형
- 자바 wrapper형
- String
- java.util.Date
- java.sql.Date
- java.math.BigDecimal
- java.math.BigInteger
4.6.2 IDENTITY 전략
- 기본 키 생성을 데이터베이스 위임하는 전략
- @GeneratedValue(strategy = GenerationType.IDENTITY)
- 단순하고 사용하기 쉬우나, 배치 삽입(batch insert) 시 효율이 떨어질 수 있습니다.
<aside> 💡
엔터티가 영속 상태가 되려면 식별자가 반드시 필요하다. 그런데 IDENTITY 식별자 생성 전략은 엔터티를 데이터베이스에 저장해야 식별자를 구할 수 있으므로 em.persist()를 호출하는 즉시 INSERT SQL이 데이터베이스에 전달된다. 따라서 이 전략은 트랜잭션을 지원하는 쓰기 지연이 동작하지 않는다.
</aside>
4.6.3 SEQUENCE 전략
- 시퀀스를 지원하는 오라클, PostgreSQL, DB2, H2 데이터베이스에서 사용할 수 있다
- @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = “XXX_SEQ_GENERATOR”)
- Entity에 @SequenceGenerator 선언
- 성능 최적화가 가능하지만, 시퀀스를 지원하지 않는 데이터베이스에서는 사용할 수 없습니다.
4.6.4 TABLE 전략
- 모든 데이터베이스에서 사용 가능하지만, 성능이 상대적으로 낮을 수 있습니다.
4.6.5 AUTO 전략
- 기본 키 생성 전략을 JPA 구현체(Hibernate 등)에 맡깁니다. JPA가 사용하는 데이터베이스에 따라 가장 적합한 방식으로 자동 설정됩니다.
- 데이터베이스에 맞게 IDENTITY, SEQUENCE, TABLE 중 하나를 자동으로 선택합니다.
4.6.6 기본키 매핑 정리
- 영속성 컨텍스트는 엔터티를 식별자 값으로 구분하므로 엔터티를 영속 상태로 만들려면 식별자 값이 반드시 있어야 한다. em.persist()를 호출한 직후에 발생하는 일을 식별자 할당 전략별로 정리하면 다음과 같다.
- 직접할당
- em.persist()를 호출하기 전에 애플리케이션에서 직접 식별자 값을 할당해야 한다. 만약 식별자 값이 없으면 예외가 발생.
- SEQUENCE
- 데이터베이스 시퀀스에서 식별자 값을 획득한 후 영속성 컨텍스트에 저장한다.
- TABLE
- 데이터베이스 시퀀스 생성용 테이블에서 식별자 값을 획득한 후 영속성 컨텍스트에 저장한다.
- IDENTITY
- 데이터베이스에 엔터티를 저장해서 식별자 값을 획득한 후 영속성 컨텍스트에 저장한다.
- IDENTITY 전략은 테이블에 데이터를 저장해야 식별자 값을 획득할 수 있다.
<aside> 💡
권장하는 식별자 선택 전략
데이터베이스 기본 키는 다음 3가지 조건을 모두 만족해야 한다.
- null값은 허용하지 않는다
- 유일해야 한다
- 변해선 안 된다
테이블의 기본 키를 선택하는 전략은 크게 2가지가 있다.
- 자연키(natural key)
- 비즈니스에 의미가 있는 키
- 주민등록번호, 이메일, 전화번호
- 대리키(surrogate key)
- 비즈니스와 관련없는 임의로 만들어진 키, 대체 키로도 불린다
- 오라클 시퀀스, auto_increment, 키 생성 테이블 사용
자연키보다느 대리키를 권장한다
비즈니스 환경은 언젠가 변한다
JPA는 모든 엔터티에 일관된 방식으로 대리키 사용을 권장한다
</aside>
4.7 필드와 컬럼 매핑 : 레퍼런스
4.7.1 @Column : 컬럼을 매핑한다
- name
- insertable
- updatable
- table
- nullable(DDL) : 기본값 true
- unique(DDL)
- columnDefinition(DDL) : 데이터베이스 컬럼 정보를 직접 설정
- length(DDL)
- precesion, scale(DDL) : BigDecimal 타입
<aside> 💡
@Column 생략
@Column을 생략하게 되면 어떻게 될까? 대부분 @Column 속성의 기본값이 적용되는데, 자바 기본 타입일 때는 nullable 속성에 예외가 있다.
int data1;
Integer data2;
data1과 같은 자바 기본 타입에는 null 값을 입력할 수 없다. data2처럼 객체 타입일 때만 null 값이 허용된다. 따라서 자바 기본 타입인 int를 DDL로 생성할 때는 not null 제약 조건을 추가하는 게 좋다
</aside>
4.7.2 @Enumerated
- java enum 타입을매핑한다
- @Enumerated.STRING, @Enumerated.ORDINAL
4.7.3 @Temporal
- 날짜 타입을 매핑한다
4.7.4 @Lob
- BLOB, CLOB 타입을 매핑한다
4.7.5 @Transient
- 특정 필드를 데이터베이스에 매핑하지 않는다
4.7.6 @Access
- JPA가 엔터티 데이터에 접근하는 방식을 지정한다
- 2가지 타입을 섞어서 사용해도 된다
- AccessType.FIELD
- 필드에 직접 접근, private 이어도 접근 가능
- @Id를 필드에 사용하면 기본으로 적용
- AccessType.PROPERTY
- 프라퍼티 접근, Getter를 사용
4.8 정리
실전 예제 | 1. 요구사항 분석과 기본 매핑
<aside> 💡
데이터 중심 설계의 문제점
책의 예제 방식은 객체 설계를 테이블 설계에 맞춘 방법이다. 특히 테이블의 외래 키를 객체에 그대로 가져온 부분이 문제다. 왜냐하면 관계형 데이터베이스는 연관된 객체를 찾을 때 외래 키를 사용해서 조인하면 되지만 객체에는 조인이라는 기능이 없다. 객체는 연관된 객체를 찾을 때 참조를 사용해야 한다.
하지만 객체에서 참조 대신에 데이터베이스의 외래 키를 그대로 가지고 있으므로 order.getMember()처럼 객체 그래프를 탐색할 수 없고 객체의 특성도 살릴 수 없다.
객체는 외래 키 대신에 참조를 사용해야 한다.
정리하자면 객체는 참조를 사용해서 연관된 객체를 찾고 테이블은 외래 키를 사용해서 연관된 테이블을 찾으므로 둘 사이에는 큰 차이가 있다.
JPA는 객체의 참조와 테이블의 외래 키를 매핑해서 객체에서는 참조를 사용하고 테이블에서는 외래 키를 사용할 수 있도록 한다.
</aside>