반응형
지난 시간에는 JPA의 영속성 컨텍스트(Persistence Context)와 1차 캐시에 대해 살펴보았습니다.
이번 글에서는 실제 설계된 도메인 객체를 RDB 테이블과 매핑하는 방법,
즉 JPA 엔티티 매핑의 기본 개념과 어노테이션 사용법을 정리 하겠습니다.
1. JPA 엔티티(@Entity)란?
@Entity
- JPA가 관리하는 영속성 대상 클래스임을 선언합니다.
- 이 어노테이션이 붙은 클래스만이 JPA의 CRUD, 변경 감지, 지연 로딩 등의 기능을 활용할 수 있습니다.
import javax.persistence.Entity;
import javax.persistence.Id;
@Entity
public class User {
@Id
private Long id;
private String name;
// ... getter, setter, 기본생성자 등
}
엔티티 클래스 제약 사항
- 기본 생성자
- 파라미터가 없는 public 또는 protected 생성자가 반드시 필요합니다. (프록시 객체를 만들기 위해)
- final 클래스, enum, interface, inner 클래스 사용 불가
- 엔티티는 런타임에 프록시로 확장될 수 있어야 하므로 final 클래스나 enum/interface/내부 클래스(inner class)로 선언할 수 없습니다.
- final 필드 사용 불가
- JPA는 필드 값을 변경 감지하기 위해 리플렉션을 사용하므로, final 필드는 사용할 수 없습니다.
더보기
JPA의 지연 로딩과 프록시 객체
- 지연 로딩(Lazy Loading) 개념
- 엔티티 조회 시, 연관된 다른 엔티티를 즉시 함께 가져오지 않고
- 실제로 해당 연관 데이터를 사용할 때(getter 호출 시) 한 번 더 DB 조회를 수행하는 방식
@Entity
public class Post {
@Id
@GeneratedValue
private Long id;
private String title;
@ManyToOne(fetch = FetchType.LAZY) // ← 지연 로딩 설정
private User author; // ← 이 부분이 지연 로딩 대상
}
프록시 객체(Proxy Object)
- 지연 로딩을 구현하기 위해 JPA가 생성하는 “가짜” 엔티티 객체
- 실제 엔티티 클래스를 상속해 만들고, 초기에는 최소한의 자리만 차지하다가
- 필요한 시점에 원본 데이터를 로딩
- final class가 안 되는 이유
- 프록시 객체를 만들려면 엔티티 클래스를 상속해야 하는데,
- final class는 상속이 금지되어 있어 프록시 생성이 불가
- 결과적으로 지연 로딩 기능 자체를 사용할 수 없으므로,
- JPA 엔티티에는 final class를 허용하지 않음
- final 필드가 안 되는 이유
- JPA는 리플렉션과 기본 생성자 + setter 호출을 통해 프록시 객체의 내부 값을 채움
- final 필드는 한번 초기화된 뒤 변경이 불가능하므로,
- 리플렉션을 통한 값 설정이 실패하고 정상 동작할 수 없음
- 따라서 엔티티의 속성(컬럼 매핑 필드)에도 final 키워드를 사용하지 말아야 함
※ JAVA record 클래스와 JPA
Java 14에 도입된 record는 불변 데이터 캐리어(Immutable Data Carrier) 로, 컴파일러가 자동으로 equals/hashCode/toString/모든 필드를 초기화하는 생성자 등을 생성해 줍니다. 일견 JPA 엔티티처럼 데이터 보관용 DTO로 유용해 보이지만, 다음 이유로 엔티티로 사용할 수 없습니다.
- 불변성(final 필드)
record의 모든 구성 요소(component)는 암묵적으로 private final 필드로 선언됩니다.
→ JPA는 영속성 컨텍스트에서 변경 감지를 위해 필드 값을 바꿀 수 있어야 하지만, final 필드이므로 불가능합니다. - 기본 생성자 부재
record는 전체 필드를 인자로 받는 생성자만 제공하고, 파라미터 없는 생성자를 생성하지 않습니다.
→ JPA 사양에서는 “파라미터 없는 기본 생성자”를 요구합니다. - 프록시(subclass) 생성 불가
JPA 구현체(예: Hibernate)는 프록시 생성이나 바이트코드 조작을 위해 엔티티 클래스를 상속하거나 바이트코드를 재작성해야 합니다.
record는 final로 간주되어 상속이 불가능합니다.
2. 테이블 매핑 어노테이션: @Table
@Entity만 선언하면 엔티티 이름과 같은 테이블에 매핑됩니다. 테이블명, 스키마, 카탈로그, 제약 조건 등을 세밀하게 지정하려면 @Table 을 함께 사용합니다.
@Entity
@Table(
name = "users", // 매핑할 테이블명
schema = "public", // 스키마
uniqueConstraints = {
@UniqueConstraint(columnNames = {"email"}) // 이메일 컬럼에 유니크 제약 걸기
}
)
public class User {
옵션 종류
- name: 매핑할 테이블명
- schema / catalog: DB 스키마/카탈로그
- uniqueConstraints: DDL 생성 시 추가할 복합 유니크 제약 조건
반응형
'프로그래밍 > JPA' 카테고리의 다른 글
| [JPA] 필드와 컬럼 매핑 (1) | 2025.06.19 |
|---|---|
| [JPA] 데이터베이스 스키마 자동 생성 (0) | 2025.06.19 |
| [JPA] JPA의 영속성 관리2 (0) | 2025.06.10 |
| [JPA] JPA 의 영속성 관리 (0) | 2025.06.10 |
| [JPA] JPA 동작 방식 (2) | 2025.06.08 |
