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. 기본 키 매핑 방법
기본 키를 매핑하는 방법은 두 가지로 구분된다:
- 직접 할당: @Id만 사용
- 자동 생성: @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. 요구사항 분석
기능 요구사항
- 회원은 상품을 주문할 수 있다
- 주문 시 여러 종류의 상품을 선택할 수 있다
기능 목록
- 회원 기능: 회원등록, 회원조회
- 상품 기능: 상품등록, 상품수정, 상품조회
- 주문 기능: 상품주문, 주문내역조회, 주문취소
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의 핵심 기능으로, 객체와 관계형 데이터베이스 간의 매핑을 효과적으로 수행한다. 주요 포인트는 다음과 같다:
- @Entity와 @Table로 객체-테이블 매핑 기초 설정
- 데이터베이스 스키마 자동 생성으로 개발 생산성 향상
- 다양한 필드 매핑 애노테이션으로 복잡한 타입 처리
- 기본 키 매핑 전략으로 데이터베이스별 최적화
- 실전 예제 적용으로 실제 개발 시나리오 이해
적절한 엔티티 매핑은 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 |
