1. 기본 값 타입
JPA에서 데이터 타입은 엔티티 타입과 값 타입으로 나뉜다.
엔티티 타입
- @Entity로 정의된 객체
- 식별자(ID)가 있어 데이터를 지속적으로 추적할 수 있음
- 변경되더라도 ID가 유지되므로 동일한 엔티티로 인식
- 예시: Member, Order 등
값 타입
- int, double, String 같은 단순한 값
- 식별자가 없고 변경 시 추적 불가능
- 예시: 주소(Address), 근무 기간(Period)
값 타입 분류
- 기본 값 타입: int, Integer, String
- 임베디드 타입(복합 값 타입): 여러 값 타입을 묶어서 사용 (@Embeddable)
- 컬렉션 값 타입: 값 타입을 컬렉션으로 저장 (@ElementCollection)
기본 값 타입 예제
@Entity
public class Member {
@Id @GeneratedValue
private Long id;
private String name; // 값 타입 (String)
private int age; // 값 타입 (int)
}
값 타입은 엔티티의 생명 주기에 의존하며, 엔티티가 삭제되면 값도 함께 삭제된다.
2. 임베디드 타입(복합 값 타입)
임베디드 타입이란?
- JPA에서 새로운 값 타입을 직접 정의할 수 있음
- 여러 개의 기본 값 타입을 하나의 객체로 묶어 사용
- @Embeddable + @Embedded를 사용하여 선언
- 예시: 주소(Address), 근무 기간(Period)
임베디드 타입 적용 예제
@Embeddable
public class Address {
private String city;
private String street;
private String zipcode;
}
@Entity
public class Member {
@Id @GeneratedValue
private Long id;
private String name;
@Embedded // 임베디드 값 타입 사용
private Address homeAddress;
}
장점
- 재사용 가능
- 응집력 증가 (관련 필드를 하나의 객체로 묶어 관리)
- 엔티티를 더 세밀하게 설계 가능
3. 값 타입과 불변 객체
값 타입은 불변(immutable) 객체로 만들어야 안전하다.
값 타입을 여러 엔티티에서 공유하면 부작용(side effect)이 발생할 수 있기 때문이다.
값 타입 공유의 문제
Member member1 = new Member();
member1.setHomeAddress(new Address("서울", "강남", "12345"));
Member member2 = new Member();
member2.setHomeAddress(member1.getHomeAddress()); // 같은 주소를 공유
member2.getHomeAddress().setCity("부산"); // member1도 부산으로 변경됨
해결 방법: 값 타입을 불변 객체로 설계
@Embeddable
public class Address {
private final String city;
private final String street;
private final String zipcode;
// 생성자로만 값 설정 (Setter 제거)
public Address(String city, String street, String zipcode) {
this.city = city;
this.street = street;
this.zipcode = zipcode;
}
}
불변 객체를 사용하면 값이 변경될 일이 없으므로 부작용이 사라진다.
4. 값 타입의 비교
값 타입은 값이 같으면 같은 것으로 간주해야 한다.
비교 방식
- 동일성(identity) 비교: == (참조 비교)
- 동등성(equivalence) 비교: equals() (값 비교)
값 타입 비교 예제
Address a = new Address("서울");
Address b = new Address("서울");
System.out.println(a == b); // false (참조 다름)
System.out.println(a.equals(b)); // true (값이 같음)
값 타입을 올바르게 비교하려면 equals() 메서드를 재정의해야 한다.
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Address address = (Address) o;
return city.equals(address.city) &&
street.equals(address.street) &&
zipcode.equals(address.zipcode);
}
5. 값 타입 컬렉션
값 타입을 컬렉션으로 저장하려면 @ElementCollection을 사용해야 한다.
값 타입 컬렉션 매핑
@Entity
public class Member {
@Id @GeneratedValue
private Long id;
private String name;
@ElementCollection
@CollectionTable(name = "address", joinColumns = @JoinColumn(name = "member_id"))
private List<Address> addresses = new ArrayList<>();
}
값 타입 컬렉션의 특징
- 엔티티가 삭제되면 컬렉션도 함께 삭제됨
- 지연 로딩(Lazy Loading) 적용
- 값 변경 시 기존 데이터를 삭제하고 새로운 데이터를 삽입함
6. 정리
엔티티 타입 vs 값 타입
- 엔티티 타입: @Entity 사용, 식별자 존재, 생명주기 관리 가능
- 값 타입: 식별자 없음, 불변 객체로 사용하는 것이 안전
값 타입 활용 방법
- 임베디드 타입(@Embedded): 관련 데이터를 하나의 객체로 묶어서 사용
- 값 타입 컬렉션(@ElementCollection): 컬렉션 형태로 저장 (하지만 변경 시 전체 삭제 후 재삽입됨)
- 불변 객체로 설계하여 데이터 일관성을 유지
값 타입은 단순한 데이터를 다룰 때만 사용하고, 지속적인 추적이 필요한 경우 엔티티를 사용해야 한다.
반응형
'Backend > JPA' 카테고리의 다른 글
JPA (Spring Data JPA) - 사용자 정의 리포지토리 개념과 구현 방법 (0) | 2025.03.12 |
---|---|
JPA (Spring Data JPA) - 쿼리 메소드 기능 (예제 코드) (0) | 2025.03.11 |
JPA - 영속성 전이(CASCADE)와 고아 객체(부모 엔티티를 통해 자식의 생명주기 관리) (0) | 2025.02.24 |
JPA - 프록시와 지연 로딩 (불필요한 데이터 조회 방지) (0) | 2025.02.24 |
JPA 고급 매핑 - 상속관계 매핑과 @MappedSuperclass (테이블 구조 상속화 및 공통 엔티티 관리) (0) | 2025.02.21 |