4. 엔티티 매핑

2025. 6. 12. 17:41Spring/JPA

[목차]

1. 엔티티 매핑 개요
 1) 정의
 2) 대표 어노테이션

 

2. 객체-테이블 매핑
 1) @Entity
 3) @Table

 

3. 데이터베이스 스키마 자동 생성
 1) 기능 설명
 2) 설정 옵션 
 3) 권장 사용 환경 

 

4. 필드-컬럼 매핑
 1) @Column 속성 정리
 2) @Enumerated
 3) @Temporal
 4) @Lob
 5) @Transient

 

5. 기본 키 매핑
    5-1. 기본 키 매핑 방법

    5-2. @GeneratedValue의 전략(strategy)별 비교

        1) IDENTITY 전략

        2) SEQUENCE 전략 

        3) TABLE 전략 

        4)  왜 allocationSize 기본값이 50일까?

    5-3. 권장하는 식별자 전략 


1. 엔티티 매핑 개요

1) 정의

JPA에서 엔티티 매핑은 객체와 테이블을 매핑하는 작업
이를 통해 객체 중심의 도메인 모델을 구성하고, 관계형 DB와 연동할 수 있다

2) 대표 어노테이션

매핑 어노테이션 설명
객체-테이블
@Entity 이 클래스는 JPA가 관리하는 엔티티임을 명시
@Table 매핑할 테이블을 설정
필드-컬럼 @Column 필드 - 컬럼 매핑
기본키 
@Id 기본 키 지정
연관관계  @ManyToOne
다대일
@JoinColumn 조인 

2. 객체 - 테이블 매핑

1) @Entity

  • JPA가 관리하는 객체로 만들기 위한 어노테이션
  • 클래스에 붙여야 함
  • 필수 조건
    • 파라미터 없는 기본 생성자 필수 (public 또는 protected 생성자), JPA 라이브러리가 사용하기 때문에 
    • class: final, enum, interface, inner 사용 불가
    • 필드: final 사용 불가
  • 속성 
속성 설명  기본값 
name JPA에서 사용할 엔티티 이름 지정 클래스 이름 (권장) 

2) @Table

  • 엔티티와 매핑할 DB 테이블 지정
  • 속성
속성 설명 기본값
name 매핑할 테이블 이름 엔티티 이름
catalog DB catalog 없음
schema DB schema 없음
uniqueConstraints 유니크 제약 조건 설정 (DDL 생성 시 사용)
컬럼에서 unique로 설정하는 것 보다
Table에서 uniqueConstraints로 설정하는 것이 좋음 
없음
 

3. 데이터베이스 스키마 자동 생성

1) 설명

  • DDL을 애플리케이션 실행 시점에 자동으로 생성
  • 객체를 중심으로 테이블을 자동 생성 (테이블 만들고 객체 만드는 개발 순서 반대로 가능해짐) 
  • DB 방언(dialect)을 활용해 DB에 맞는 적절한 DDL 생성 
  • 개발 환경에서는 매우 유용하지만 운영 환경에서는 사용 주의 
    • 운영 환경에서 DDL 자동 변경은 데이터 유실, 성능 문제 및 서비스 장애를 유발할 수 있다.
    • 따라서 스키마 변경은 수동 SQL로, 운영 전 충분한 테스트 후 반영하는 것이 안전
    • 또한 SQL 스크립트도 참고는 하되 운영에선 다듬어서 사용해야 한다. 

2) 설정 옵션 

// persistence.xml
<property name="hibernate.hbm2ddl.auto" value="create" />
옵션 설명
create 기존 테이블 삭제 후 새로 생성 (DROP + CREATE)
create-drop create와 같지만, 애플리케이션 종료 시 테이블 삭제
update 변경된 부분만 반영 (운영 DB에 사용 금지)
validate 매핑만 검증 (테이블은 변경 X)
none 자동 생성 사용 안 함

3) 권장 사용 환경

환경 권장 옵션
개발 초기 create, update
(*운영엔 절대 안됨*)
테스트 서버 update, validate
(create하면 테스트 데이터 날라감)
운영/스테이징 validate, none

 

4. 객체 필드 - 테이블 컬럼 매핑

1) @Column 속성 정리

속성 설명 기본값
name 매핑할 컬럼 이름 필드 이름
insertable / updatable 등록/수정 가능 여부 true
nullable (DDL용) null 허용 여부  true
unique (DDL용) 유니크 제약 조건 (간단하게 설정) false
columnDefinition (DDL용) 컬럼 정의 직접 작성 (ex. varchar(100) default 'EMPTY') DB 방언에 따라 자동 생성
length (DDL용) 문자열 길이 (String 타입에만) 255
precision / scale (DDL용) 소수점 포함 숫자의 전체 자릿수 / 소수 자릿수 (BigDecimal에만 사용) 없음
  • 필드에 아무 어노테이션도 달지 않으면 @Column 속성의 기본값으로 자동 매핑된다
  • 날짜, enum, BLOB/CLOB 등 특수 타입은 명시적인 어노테이션이 꼭 필요
2) @Enumerated
  • enum 매핑 
    • EnumType.ORDINAL: enum 순서(1,2,3..)를 DB에 저장 → 기본값
      단, enum 순서가 바뀌면 데이터 오류 발생! 사용❌
    • EnumType.STRING: enum 이름(USER, ADMIN..)을 DB에 저장 사용 권장

3) @Temporal 

  • java.util.Date, Calendar 사용 시 필요
  • Java 8 LocalDate는 생략 가능
  • 속성 
속성 설명
DATE 날짜 (yyyy-MM-dd)
TIME 시간 (HH:mm:ss)
TIMESTAMP 날짜 + 시간 (yyyy-MM-dd HH:mm:ss)

4) @Lob

  • VARCHAR를 넘어가는 문자열을 넣고 싶은 경우 사용
  • 문자(String, char[])면 CLOB, 나머지(byte[])는 BLOB으로 매핑

5) @Transient

  • DB에 저장 X, 조회 X
  • 애플리케이션 내부 계산 값 등에 사용

 

5. 기본 키 매핑

5-1. 기본 키 매핑 방법

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
  • 기본 키 직접 할당: @Id만 사용
  • 자동 생성: @GeneratedValue 함께 사용 

5-2. @GeneratedValue의 전략(strategy)별 비교

전략 ID생성 주체 설명  사용 DB
IDENTITY DB
기본키 생성을 DB에 위임
(AUTO_INCREMENT 기반)
 MySQL, MariaDB, MsSQL
SEQUENCE JPA
@SequenceGenerator
DB 시퀀스 오브젝트 사용 Oracle, PostgreSQL, H2 
TABLE JPA
@TableGenerator 
키 생성용 테이블을 만들어서
DB 시퀀스를 흉내내는 전략
모든 DB에 사용가능
(성능 낮음)

AUTO   DB 방언에 따라 위의 3가지 중
한 개 자동 지정됨 

(기본 값)
 
1) IDENTITY 전략
DB가 ID를 생성하고, JPA는 그걸 나중에 받아오는 방식
  1. em.persist(entity) 호출
  2. JPA는 ID를 아직 모름 → DB에 INSERT SQL을 바로 실행함 (쓰기 지연 X) 
    INSERT INTO member (name, age, ...) VALUES (?, ?, ...);
    • JPA는 보통 트랜잭션 커밋 시점에 INSERT SQL 실행
    • 그러나! AUTO_ INCREMENT는 데이터베이스에 INSERT SQL을 실행한 이후에 ID 값을 알 수 있음
    • 그러나! 영속성 컨텍스트 1차 캐시에 값을 넣으려면 ID 값이 필요함
    • 따라서 IDENTITY 전략만 예외적으로 em.persist() 시점에 즉시 INSERT SQL 실행하고 DB에서 식별자를 조회
  3. DB가 AUTO_INCREMENT로 ID 값을 자동 생성
  4. JPA는 DB가 생성한 ID 값을 받아와서 → 엔티티의 id 필드에 설정함
  5. 이제 1차 캐시에 등록 가능 → 이후는 다른 전략과 동일하게 동작 (flush, commit 등)

2) SEQUENCE 전략

DB 시퀀스 오브젝트에서 값을 미리 가져옴

  1. @SequenceGenerator로 시퀀스 매핑
  2. em.persist() 하면, INSERT 전에 JPA가 아래 쿼리를 먼저 실행함
    SELECT MEMBER_SEQ.NEXTVAL FROM DUAL;
  3. 이 결과로 받은 값을 ID로 먼저 세팅
  4. 실제 INSERT는 트랜잭션 커밋 시점에 실행됨 (쓰기 지연 O)
@SequenceGenerator 속성 설명 기본값
name 식별자 생성기 이름 필수
sequenceName DB 시퀀스 이름 hibernate_sequence
initialValue (DDL용) 초기 시작 값 1
allocationSize 시퀀스 한 번 호출 시 증가값
성능 최적화에 사용됨 
50 (1로 설정 시 성능↓)

3) TABLE 전략

키 생성 테이블에서 값을 미리 가져옴

  1. @TableGenerator로 테이블(MY_SEQUENCES 등) 생성
  2. em.persist() 시, 다음 쿼리로 ID 값을 먼저 조회 & 증가
    SELECT next_val FROM MY_SEQUENCES WHERE sequence_name = 'MEMBER_SEQ'; 
    UPDATE MY_SEQUENCES SET next_val = next_val + 1 WHERE sequence_name = 'MEMBER_SEQ';
  3. 받은 값을 엔티티의 ID로 세팅
  4. INSERT는 나중에 실행 (쓰기 지연 O)
@TableGenerator  속성 설명 기본값
table 키 생성용 테이블 이름 hibernate_sequences
pkColumnName 시퀀스명 컬럼 sequence_name
valueColumnName 시퀀스 값 컬럼 next_val
pkColumnValue 사용할 키 이름 엔티티 이름
allocationSize 증가 단위 50

4)  왜 allocationSize 기본값이 50일까?

  • INSERT할 때마다 시퀀스를 SELECT하면 DB 부하 커짐
  • 그래서 JPA는 기본적으로 한 번에 50개를 미리 확보해서
    50건의 persist를 DB 접근 없이 메모리에서 처리
  • 단! allocationSize를 너무 크게 설정하면?
    • ID 낭비: 앱이 재시작되면 미사용 ID 버려짐 → ID가 툭툭 점프함
    • ID 연속성 없음: 사용자 입장에서 ID가 갑자기 10만 뛰면 당황할 수 있음
    • 다중 서버 환경: 각 서버가 큰 범위 가져가면 관리 어려움, DB 시퀀스와 불일치 위험

5-3. 권장하는 식별자 전략 

  • Long형 + 대체키 키 생성 전략 사용
  • Long형 사용 이유
    • Integer보다 Long이 더 크기가 크긴 하지만 
    • 나중에 범위 넘어갔을때 Long으로 바꾸는게 더 힘듦 
  • 대체키 사용 이유
    • 기본키 제약 조건: null 아님 + 유일 + 변하면 안됨
    • 미래까지 이 조건을 만족하는 자연키(비즈니스와 관련있는 값)를 찾기 어렵다. 주민등록번호도 적절하지 않음. 
    • 따라서 대체키(대리키)를 사용 권장