[Basic-3] 엔터티 매핑 (Entity Mapping)

2026. 1. 6. 11:03·Spring/JPA

1. 객체와 테이블 매핑 기초

1.1. @Entity 애노테이션

@Entity가 붙은 클래스는 JPA가 관리하는 엔티티가 된다. JPA를 사용해서 테이블과 매핑할 모든 클래스는 @Entity 애노테이션이 필수다.

@Entity
public class Member {
    @Id
    private Long id;
    private String name;

    // 기본 생성자 필수
    public Member() {}

    // 매개변수 있는 생성자
    public Member(Long id, String name) {
        this.id = id;
        this.name = name;
    }
}

@Entity 사용 시 주의사항

  • 기본 생성자 필수 (파라미터가 없는 public 또는 protected 생성자)
  • final 클래스, enum, interface, inner 클래스에는 사용할 수 없음
  • 저장할 필드에 final 사용 불가

@Entity 속성

  • name: JPA에서 사용할 엔티티 이름 지정
  • 기본값: 클래스 이름 (예: "Member")
  • 같은 클래스 이름이 없으면 가급적 기본값 사용 권장

1.2. @Table 애노테이션

@Table은 엔티티와 매핑할 테이블을 지정한다. 생략하면 엔티티 이름을 테이블 이름으로 사용한다.

@Entity
@Table(name = "MEMBER_TABLE")
public class Member {
    @Id
    private Long id;
    private String name;
}

@Table 속성

  • name: 매핑할 테이블 이름
  • catalog: 데이터베이스 catalog 매핑
  • schema: 데이터베이스 schema 매핑
  • uniqueConstraints: DDL 생성 시 유니크 제약 조건 생성
@Entity
@Table(
    name = "MEMBER",
    uniqueConstraints = {
        @UniqueConstraint(
            name = "NAME_AGE_UNIQUE",
            columnNames = {"NAME", "AGE"}
        )
    }
)
public class Member {
    @Id
    private Long id;

    @Column(name = "NAME")
    private String name;

    private Integer age;
}

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

2.1. 스키마 자동 생성 기능

JPA는 DDL(Data Definition Language)을 애플리케이션 실행 시점에 자동 생성할 수 있다. 이는 테이블 중심 개발에서 객체 중심 개발로 전환하는 데 큰 도움이 된다.

spring:
  jpa:
    hibernate:
      # ddl-auto 설정 (none, validate, update, create, create-drop)
      ddl-auto: update
    properties:
      hibernate:
        # 실행되는 SQL을 콘솔에 출력
        show_sql: true
        # 출력되는 SQL을 보기 좋게 정렬
        format_sql: true
        # SQL에 주석을 포함하여 출력
        use_sql_comments: true
    # 하이버네이트가 생성하는 쿼리를 로그로 확인 (선택 사항)
    show-sql: true

2.2. hibernate.hbm2ddl.auto 옵션

옵션  설명  사용 시기
create 기존 테이블 삭제 후 다시 생성 (DROP + CREATE) 개발 초기 단계
create-drop create와 같으나 종료시점에 테이블 DROP 테스트 환경
update 변경분만 반영 개발, 테스트 서버
validate 엔티티와 테이블이 정상 매핑되었는지 확인 스테이징 서버
none 사용하지 않음 운영 서버

주의사항

  • 운영 장비에는 절대 create, create-drop, update 사용 금지
  • 개발 초기 단계: create 또는 update
  • 테스트 서버: update 또는 validate
  • 스테이징과 운영 서버: validate 또는 none

2.3. DDL 생성 기능

JPA는 애노테이션을 기반으로 DDL을 생성할 때 추가적인 제약조건을 설정할 수 있다.

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

    @Column(nullable = false, length = 10)
    private String name;

    @Column(unique = true)
    private String email;
}

DDL 생성 결과

CREATE TABLE MEMBER (
    id BIGINT NOT NULL,
    name VARCHAR(10) NOT NULL,
    email VARCHAR(255) UNIQUE,
    PRIMARY KEY (id)
);

3. 필드와 컬럼 매핑

3.1. 기본 매핑 어노테이션

다양한 필드 타입을 데이터베이스 컬럼에 매핑하기 위한 애노테이션들:

@Entity
public class Member {
    @Id
    private Long id;

    @Column(name = "name", nullable = false, length = 10)
    private String username;

    private Integer age;

    @Enumerated(EnumType.STRING)
    private RoleType roleType;

    @Temporal(TemporalType.TIMESTAMP)
    private Date createdDate;

    @Lob
    private String description;

    @Transient
    private Integer tempValue;
}

3.2. @Column 상세 속성

속성  설명  기본값
name 필드와 매핑할 컬럼 이름 필드 이름
nullable null 값 허용 여부 true
unique 유니크 제약조건 false
length 문자 길이 제약조건 (String 타입만) 255
columnDefinition 데이터베이스 컬럼 정보 직접 지정 -
insertable 등록 가능 여부 true
updatable 변경 가능 여부 true
@Entity
public class Product {
    @Id
    private Long id;

    @Column(
        name = "product_name",
        nullable = false,
        length = 100,
        columnDefinition = "varchar(100) default 'EMPTY'"
    )
    private String name;

    @Column(precision = 10, scale = 2)
    private BigDecimal price;
}

3.3. @Enumerated - enum 타입 매핑

자바 enum 타입을 데이터베이스에 매핑할 때 사용한다. ORDINAL 대신 STRING을 사용하는 것이 권장된다.

public enum RoleType {
    USER, ADMIN, GUEST
}

@Entity
public class Member {
    @Id
    private Long id;

    @Enumerated(EnumType.STRING)  // enum 이름을 저장
    private RoleType roleType;

    // @Enumerated(EnumType.ORDINAL) - 숫자로 저장 (비권장)
}

EnumType 비교

  • STRING: "USER", "ADMIN"처럼 enum 이름 저장
  • ORDINAL: 0, 1처럼 enum 순서 저장 (추가 시 문제 발생 가능)

3.4. @Temporal - 날짜 타입 매핑

날짜 타입(java.util.Date, java.util.Calendar)을 매핑할 때 사용한다.

@Entity
public class Member {
    @Id
    private Long id;

    @Temporal(TemporalType.DATE)
    private Date birthDate;  // 2023-10-10

    @Temporal(TemporalType.TIME)
    private Date birthTime;  // 14:30:00

    @Temporal(TemporalType.TIMESTAMP)
    private Date createdDate;  // 2023-10-10 14:30:00
}

Java 8+ 날짜 타입

@Entity
public class Member {
    @Id
    private Long id;

    private LocalDate birthDate;      // @Temporal 생략 가능
    private LocalTime birthTime;      // @Temporal 생략 가능
    private LocalDateTime createdDate; // @Temporal 생략 가능
}

3.5. @Lob - 대용량 데이터 매핑

데이터베이스 BLOB, CLOB 타입과 매핑한다.

@Entity
public class Member {
    @Id
    private Long id;

    @Lob
    private String description;  // CLOB으로 매핑

    @Lob
    private byte[] image;        // BLOB으로 매핑
}

@Lob 매핑 규칙

  • 문자 타입(String, char[], java.sql.CLOB): CLOB 매핑
  • 바이트 타입(byte[], java.sql.BLOB): BLOB 매핑

3.6. @Transient - 매핑 제외

특정 필드를 데이터베이스에 매핑하지 않을 때 사용한다.

@Entity
public class Member {
    @Id
    private Long id;

    private String name;

    @Transient
    private String temporaryData;  // DB에 저장되지 않음

    @Transient
    private Integer calculatedValue;  // 계산된 값 저장용
}

4. 기본 키 매핑

4.1. 기본 키 매핑 방법

기본 키를 매핑하는 방법은 두 가지로 구분된다:

  1. 직접 할당: @Id만 사용
  2. 자동 생성: @GeneratedValue 사용
@Entity
public class Member {
    // 1. 직접 할당
    @Id
    private Long id;

    // 2. 자동 생성
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long autoId;
}

4.2. GenerationType 전략

JPA는 4가지 자동 생성 전략을 제공한다:

4.2.1. IDENTITY 전략

데이터베이스에 기본 키 생성을 위임하는 전략이다. 주로 MySQL, PostgreSQL에서 사용한다.

@Entity
public class Member {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
}

IDENTITY 전략 특징

  • MySQL의 AUTO_INCREMENT, PostgreSQL의 SERIAL 사용
  • em.persist() 호출 시점에 즉시 INSERT SQL 실행
  • 트랜잭션 커밋을 기다리지 않음
  • 영속성 컨텍스트의 1차 캐시를 위해 PK 조회 필요

4.2.2. SEQUENCE 전략

데이터베이스 시퀀스를 사용하는 전략이다. 오라클, PostgreSQL, H2 데이터베이스에서 사용한다.

@Entity
@SequenceGenerator(
    name = "MEMBER_SEQ_GENERATOR",
    sequenceName = "MEMBER_SEQ",
    initialValue = 1,
    allocationSize = 1
)
public class Member {
    @Id
    @GeneratedValue(
        strategy = GenerationType.SEQUENCE,
        generator = "MEMBER_SEQ_GENERATOR"
    )
    private Long id;
}

@SequenceGenerator 속성

  • name: 식별자 생성기 이름 (필수)
  • sequenceName: 데이터베이스 시퀀스 이름
  • initialValue: 초기값 (기본값: 1)
  • allocationSize: 증가값 (기본값: 50, 성능 최적화용)

allocationSize 최적화

@SequenceGenerator(
    name = "MEMBER_SEQ_GENERATOR",
    sequenceName = "MEMBER_SEQ",
    initialValue = 1,
    allocationSize = 50  // 데이터베이스에 한 번 접근하여 50개의 ID 미리 확보
)

4.2.3. TABLE 전략

키 생성 전용 테이블을 사용하는 전략이다. 모든 데이터베이스에서 사용 가능하다.

@Entity
@TableGenerator(
    name = "MEMBER_SEQ_GENERATOR",
    table = "MY_SEQUENCES",
    pkColumnValue = "MEMBER_SEQ",
    allocationSize = 1
)
public class Member {
    @Id
    @GeneratedValue(
        strategy = GenerationType.TABLE,
        generator = "MEMBER_SEQ_GENERATOR"
    )
    private Long id;
}

생성되는 테이블 구조

CREATE TABLE MY_SEQUENCES (
    sequence_name VARCHAR(255) NOT NULL,
    next_val BIGINT,
    PRIMARY KEY (sequence_name)
);

4.2.4. AUTO 전략

데이터베이스 방언에 따라 자동으로 전략을 선택한다. 기본값이다.

@Entity
public class Member {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)  // 생략 가능
    private Long id;
}

4.3. 권장하는 식별자 전략

기본 키 제약 조건

  • null이 아니어야 함
  • 유일해야 함
  • 변하지 않아야 함

자연키 vs 대리키

  • 자연키: 비즈니스 의미를 가진 키 (주민등록번호, 이메일 등)
  • 대리키: 비즈니스와 무관한 임의의 키

권장 전략

  • Long형 사용 (Integer는 데이터가 많아지면 부족할 수 있음)
  • 대리키 사용
  • 키 생성 전략 사용 (SEQUENCE 또는 IDENTITY)

5. 실전 예제: 온라인 쇼핑몰

5.1. 요구사항 분석

기능 요구사항

  • 회원은 상품을 주문할 수 있다
  • 주문 시 여러 종류의 상품을 선택할 수 있다

기능 목록

  1. 회원 기능: 회원등록, 회원조회
  2. 상품 기능: 상품등록, 상품수정, 상품조회
  3. 주문 기능: 상품주문, 주문내역조회, 주문취소

5.2. 도메인 모델 분석

관계 분석

  • 회원 ↔ 주문: 일대다 관계 (한 회원이 여러 주문 가능)
  • 주문 ↔ 상품: 다대다 관계 (주문상품 엔티티로 풀어냄)

5.3. 엔티티 설계와 매핑

// 회원 엔티티
@Entity
@Table(name = "MEMBER")
public class Member {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "name", nullable = false, length = 10)
    private String name;

    @Column(unique = true)
    private String email;

    private LocalDateTime createdDate;

    @Enumerated(EnumType.STRING)
    private MemberStatus status;
}
// 상품 엔티티
@Entity
@Table(name = "PRODUCT")
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String name;

    @Column(precision = 10, scale = 2)
    private BigDecimal price;

    private Integer stockQuantity;

    @Enumerated(EnumType.STRING)
    private ProductCategory category;
}

// 주문 엔티티
@Entity
@Table(name = "ORDERS")
public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne
    @JoinColumn(name = "member_id")
    private Member member;

    @OneToMany(mappedBy = "order")
    private List<OrderItem> orderItems = new ArrayList<>();

    private LocalDateTime orderDate;

    @Enumerated(EnumType.STRING)
    private OrderStatus status;
}
// 주문상품 엔티티 (다대다 관계 해소)
@Entity
@Table(name = "ORDER_ITEM")
public class OrderItem {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne
    @JoinColumn(name = "order_id")
    private Order order;

    @ManyToOne
    @JoinColumn(name = "product_id")
    private Product product;

    private Integer orderPrice;
    private Integer count;
}

 

5.4. 데이터 중심 설계의 문제점

현재 방식의 한계

  • 객체 설계를 테이블 설계에 맞춘 방식
  • 테이블의 외래키를 객체에 그대로 가져옴
  • 객체 그래프 탐색이 불가능
  • 참조가 없으므로 UML 표현 부정확

개선 방향

  • 객체지향 설계 원칙 적용
  • 연관관계 매핑을 통한 객체 그래프 탐색 가능
  • 엔티티 간의 참조 관계 명확화

6. 실무 적용 팁

6.1. 엔티티 설계 시 고려사항

기본 생성자 접근 제어

@Entity
public class Member {
    @Id
    @GeneratedValue
    private Long id;

    protected Member() {}  // JPA용 protected 생성자

    public Member(String name) {  // 비즈니스 로직용 생성자
        this.name = name;
        this.createdDate = LocalDateTime.now();
    }
}

DDL 자동 생성 활용

# 개발 환경
hibernate.hbm2ddl.auto=update

# 테스트 환경
hibernate.hbm2ddl.auto=validate

# 운영 환경
hibernate.hbm2ddl.auto=none

복합 유니크 제약조건

@Entity
@Table(name = "MEMBER", uniqueConstraints = {
    @UniqueConstraint(
        name = "UK_MEMBER_EMAIL",
        columnNames = {"email"}
    )
})
public class Member {
    @Column(unique = true)  // 단일 컬럼 유니크는 @Column으로도 가능
    private String email;
}

6.2. 성능 고려사항

SEQUENCE 전략의 allocationSize 최적화

@SequenceGenerator(
    name = "MEMBER_SEQ",
    sequenceName = "member_seq",
    initialValue = 1,
    allocationSize = 50  // 데이터베이스 호출 횟수 감소
)

기본값 설정으로 NULL 방지

@Column(
    name = "status",
    nullable = false,
    columnDefinition = "varchar(20) default 'ACTIVE'"
)
private String status;

6.3. 유지보수성 고려사항

엔티티 이름 명확화

@Entity(name = "ShopMember")  // 테이블명과 엔티티명 분리
@Table(name = "MEMBER")
public class Member {
    // ...
}

컬럼 정의 상세화

@Column(
    name = "product_description",
    length = 1000,
    columnDefinition = "TEXT"
)
private String description;

7. 정리

엔티티 매핑은 JPA의 핵심 기능으로, 객체와 관계형 데이터베이스 간의 매핑을 효과적으로 수행한다. 주요 포인트는 다음과 같다:

  1. @Entity와 @Table로 객체-테이블 매핑 기초 설정
  2. 데이터베이스 스키마 자동 생성으로 개발 생산성 향상
  3. 다양한 필드 매핑 애노테이션으로 복잡한 타입 처리
  4. 기본 키 매핑 전략으로 데이터베이스별 최적화
  5. 실전 예제 적용으로 실제 개발 시나리오 이해

적절한 엔티티 매핑은 JPA 기반 애플리케이션의 성능, 유지보수성, 확장성에 직접적인 영향을 미친다. 데이터베이스 스키마 자동 생성은 개발 단계에서만 사용하고, 운영 환경에서는 철저한 검증 후 수동 적용이 필요하다는 점을 명심해야 한다.

'Spring > JPA' 카테고리의 다른 글

[Basic-5] 연관관계 매핑 심화  (0) 2026.01.06
[Basic-4] 연관관계 매핑 기초  (0) 2026.01.06
[Basic-2] 영속성 컨텍스트 (Persistence Context)  (0) 2026.01.06
[Basic-1] JPA 시작  (0) 2026.01.05
[Optimization-7] JPA: 벌크 연산 모니터링  (0) 2025.12.27
'Spring/JPA' 카테고리의 다른 글
  • [Basic-5] 연관관계 매핑 심화
  • [Basic-4] 연관관계 매핑 기초
  • [Basic-2] 영속성 컨텍스트 (Persistence Context)
  • [Basic-1] JPA 시작
h6bro
h6bro
백엔드 개발자의 기술 블로그
  • h6bro
    Jun's Tech Blog
    h6bro
  • 전체
    오늘
    어제
    • 분류 전체보기 (250) N
      • Java (18)
        • Core (9)
        • Design Pattern (9)
      • Spring (80)
        • Core (24)
        • MVC (6)
        • DB (10)
        • JPA (26)
        • Monitoring (3)
        • Security (11)
        • WebSocket (0)
      • Database (33)
        • Redis (15)
        • MySQL (18)
      • MSA (25) N
        • MSA 기본 (11)
        • MSA 아키텍처 (14) N
      • Kafka (30) N
        • Core (18) N
        • Connect (12)
      • ElasticSearch (11)
        • Search (11)
        • Logging (0)
      • Test (4)
        • k6 (4)
      • Docker (9)
      • CI&CD (10)
        • GitHub Actions (6)
        • ArgoCD (4)
      • Kubernetes (18)
        • Core (12)
        • Ops (6)
      • Cloud Engineering (4)
        • AWS Infrastructure (3)
        • AWS EKS (1)
        • Terraform (0)
      • Project (8)
        • LinkFolio (1)
        • Secondhand Market (7)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

    • Cloud Engineering 포스팅 정리
  • 인기 글

  • 태그

    ㅈ
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
h6bro
[Basic-3] 엔터티 매핑 (Entity Mapping)
상단으로

티스토리툴바