본문으로 건너뛰기
홈
기술
기술 전체
프로그래밍68
컴퓨터 과학63
AI48
웹 개발36
인프라33
데이터31
소프트웨어 공학18
소개
← 목록으로웹 개발 › 백엔드 › JPA

4. Entity Mapping(엔티티 매핑)

목차

4. Entity Mapping(엔티티 매핑)

JPA의 기본은 엔티티와 테이블을 정확하게 매핑하는 것이다.

1. 대표적인 어노테이션
  • 객체와 테이블 매핑 : @Entity, @Table
  • 기본 키 매핑 : @Id
  • 필드와 컬럼 매핑 : @Column
  • 연관관계 매핑 : @ManyToOne, @JoinColumn
(1) @Entity
  • 테이블과 매핑할 때 사용하는 어노테이션으로 클래스위에 붙여야 한다. (Entity Class 라고한다)
    • name 속성 : 사용할 엔티티 이름을 지정하고 기본값은 클래스명을 이름으로 사용한다.

주의 사항

  • 기본생성자 필수
  • final, enum, interface, inner 클래스에는 사용불가
  • 저장할 필드에 final을 사용하면 안된다.
@Table
  • 엔티티와 매핑할 테이블을 지정한다. 엔티티 클래스에 매핑할 테이블 정보를 알려주므로 name 속성을 이용하여 테이블을 매핑할 수 있다(기본 값 클래스명).
(3) @Id
  • 엔티티 클래스의 필드를 테이블의 기본키에 매핑할 수 있다.
(4) @Column
  • 필드를 컬럼에 매핑할 수 있고 name 속성을 통해 테이블의 필드를 매핑할 수 있다.
    • name : 컬럼 명 매핑
    • nullable : DDL시 null 여부 (이기능들은 DDL 자동등록 시만 사용된다.)
    • length : DDL시 문자 크기를 지정 (이기능들은 DDL 자동등록 시만 사용된다.)
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import java.time.Instant;

@Entity
@Table(name = "members")
public class Member {
    @Id
    @Column(name = "member_id")
    private Long id;

    @Column(name = "user_name", nullable = false, length = 100)
    private String userName;

    private Instant createdAt;

    @Enumerated(EnumType.STRING)
    private RoleType roleType;

    protected Member() { }

    public Member(Long id, String userName, RoleType roleType) {
        this.id = id;
        this.userName = userName;
        this.roleType = roleType;
        this.createdAt = Instant.now();
    }
}
public enum RoleType { ADMIN, USER }
2. 데이터베이스 스키마 (DDL) 자동 생성
  • hibernate.hbm2ddl.auto=create는 실습용 빈 데이터베이스에서만 사용한다. 실행할 때 기존 테이블이 삭제·재생성될 수 있으므로 운영 DB에 적용하지 않는다. 운영 스키마는 검토된 마이그레이션으로 관리한다.
<property name="hibernate.hbm2ddl.auto" value="create"/>

hibernate.show_sql 속성을 true로 지정해주면 콘솔에서 테이블 생성 로그를 확인 할 수 있다.

<property name="hibernate.show_sql" value="true"/>
3. 기본키 생성 종류
4. 매핑 어노테이션
@Enumerated : 자바의 enum 타입을 매핑
  • EnumType.ORDINAL : enum 순서를 데이터베이스에 저장. 중간에 값을 추가하면 기존 행의 의미가 달라질 수 있다.
  • EnumType.STRING : enum 이름을 데이터베이스에 저장
@Temporal : 날짜 타입을 매핑
  • TemporalType.DATE : 날짜, 데이터베이스 date 타입과 매핑(Ex. 2019-10-14)
  • TemporalType.TIME : 시간, 데이터베이스 time 타입과 매핑(Ex. 11:11:11)
  • TemporalType.TIMESTAMP : 날짜와 시간, 데이터베이스 TIMESTAMP 타입과 매핑(Ex. 2019-10-14 11:11:11)
@Lob : BLOB, CLOB 타입을 매핑
@Transient : 특정 필드를 데이터베이스에 매핑하지 않는다.
@Access : JPA가 엔티티에 접근하는 방식을 지정

필드가 테이블에 반영되는 순서

위 Member에서 @Id는 자바 객체의 동등성 기준이 아니라 테이블 행의 식별자를 정한다. @Table을 생략하면 공급자의 이름 지정 전략에 따라 테이블명이 달라질 수 있으므로 기존 스키마에 붙일 때 이름을 명시한다. @Column(nullable = false)는 DDL 생성 시 제약에 영향을 주지만, 애플리케이션의 모든 입력을 자동으로 검증하는 수단은 아니다. 예를 들어 빈 문자열은 SQL NOT NULL 제약에 걸리지 않을 수 있다. API 입력 검사와 데이터베이스 제약을 함께 둔다.

flowchart LR
  A["Member 생성"] --> B["persist 호출"]
  B --> C["영속성 컨텍스트에서 상태 관리"]
  C --> D["flush 때 INSERT 준비"]
  D --> E["DB의 members 테이블"]
  E --> F["커밋 또는 롤백"]

persist() 직후 항상 INSERT가 실행된다고 생각하면 쿼리 순서를 잘못 이해하기 쉽다. 공급자는 쓰기를 모았다가 flush 시점에 SQL로 보낼 수 있다. 다만 ID 생성 전략이나 쿼리 실행 때문에 더 이른 SQL이 필요할 수도 있다. SQL 로그와 트랜잭션 경계를 함께 확인해야 한다. 커밋이 실패하면 자바 객체에 ID가 들어 있어도 저장 성공으로 취급할 수 없다.

기본 키를 정할 때

기본 키를 애플리케이션이 미리 알고 있다면 위처럼 @Id 필드에 값을 넣을 수 있다. 데이터베이스가 값을 만들게 할 때는 @GeneratedValue를 사용한다. IDENTITY, SEQUENCE, TABLE, AUTO는 값이 만들어지는 곳과 SQL 실행 시점에 차이가 있다. 특히 대량 저장에서 생성 전략이 배치 INSERT에 영향을 주므로 사용 DB와 공급자의 실제 SQL을 확인한다. 외부 시스템의 회원 번호처럼 바뀔 수 있는 값을 기본 키로 쓰기보다 내부에서 안정적으로 유지할 키를 고르는 편이 관계 관리에 유리하다.

날짜·열거형·스키마를 검토할 때

Instant는 시각을 표현한다. 기존 java.util.Date나 Calendar의 날짜 정밀도를 지정할 때 @Temporal을 쓰지만, java.time 타입에 무조건 붙이는 코드는 피한다. 날짜만 필요하면 LocalDate, 시간대와 독립된 시각이 필요하면 Instant처럼 도메인의 뜻에 맞춰 타입을 정한다. DB 드라이버와 컬럼 형식이 실제로 어떻게 변환하는지 테스트한다.

EnumType.STRING은 열거형 이름을 저장하므로 순서 변경에 강하지만, 이름 자체를 바꾸면 기존 데이터와 충돌한다. 상태값을 외부 계약으로 공개했다면 이름 변경도 데이터 마이그레이션이다. EnumType.ORDINAL은 순서에 의미를 부여하므로 중간 값 추가에 취약하다. columnDefinition에 특정 DB의 SQL을 고정하면 다른 DB로 옮길 때 깨질 수 있으므로 필요한 경우에만 사용한다.

확인할 현상가능한 원인확인 방법
테이블/컬럼을 못 찾음이름 지정 전략 또는 대소문자 차이실제 DDL·SQL과 DB 스키마 비교
저장 시 NOT NULL 오류필수 필드 누락API 검증과 엔티티 생성자 점검
enum을 읽지 못함이름 변경 또는 저장 방식 변경기존 행 값과 매핑 설정 비교
날짜가 어긋남타입·시간대·드라이버 설정 불일치DB 원시 값과 애플리케이션 변환 값 비교

스키마 자동 생성은 학습용으로는 편하다. 운영에서는 생성된 DDL을 검토한 뒤 Flyway나 Liquibase 같은 마이그레이션 도구와 배포 절차로 반영한다. 매핑을 바꿀 때는 새 코드가 이전 데이터도 읽을 수 있는지 먼저 확인한다.

참고: Jakarta Persistence 사양, Jakarta Persistence API, Hibernate 스키마 관리.

같은 카테고리의 글