0. 개요
- 이번 포스팅에서는 JPA의 데이터 타입에 대해서 알아보자.
1. 값 타입
- JPA는 두 가지 데이터 타입을 사용한다.
a) Entity 타입
- JPA의 최상위 타입이다.
- @Entity로 정의된 클래스 객체를 의미한다.
- Entity 타입은 값이 변경되어도 식별자(= id, PK)를 이용하여 추적이 가능하다.
ex) 게시판의 1번 글(= 객체)의 내용이 수정 또는 삭제되어도 1번 아이디를 이용하여 객체의 상태를 추적할 수 있다.
b) 값 타입
- int, String, Integer와 같이 자바의 Primitive 또는 Wrapper 클래스를 이용하여 생성된 객체
- 식별자가 없으므로 값의 변경 시 추적이 불가능하다.
ex) int a = 100이라면, 이를 a = 200으로 변경해도 변수 a의 값이 과거에 100이었다는 것을 알 수 없다.
ex) 게시판의 1번 글의 내용이 변경되면, 과거에 1번 글의 내용이 무엇이었는지 알 수 없다.
c) 값 타입의 분류
- 값 타입은 3가지 종류로 구분된다.
→ 기본 값 타입(primitive, wrapper, String)
→ 임베디드 타입(embedded type, 복합 값 타입, 기본 값을 묶어서 하나의 값으로 사용)
→ 컬렉션 타입(collection value type, 자바 collections를 이용한 값)
2. 기본 값 타입
- 기본 값 타입은 primitive 자료형 또는 wrapper 클래스를 통해 정의되는 값을 말한다.
- 기본 값 타입의 생명 주기는 Entity에 의존한다. (Entity에 포함되는 개념이기 때문이다.)
ex) 회원 Entity를 삭제하면, 회원 Entity를 구성하는 속성 값(= 기본 값 타입) 또한 삭제된다.
- 기본 값 타입은 공유되지 않고, 공유해서도 안 된다.
ex) 회원 A의 String name 속성을 변경했는데 회원 B의 String name 속성이 변경되면 안 된다.
- 애초에 자바의 기본(primitive) 타입은 공유가 되지 않는다.
→ 아래 사진을 보면 자바의 기본 타입은 값이 복사가 되어 넘어가는 방식이지 공유되는 것이 아니다.
→ 즉, 메모리 상에서 변수 a와 b는 서로 다른 메모리 공간을 할당받고 있는 것이다.
- Wrapper 클래스를 사용하는 경우, 값은 공유되지만 값을 변경할 수 있는 방법이 없다.
→ 아래 예시를 보면, 객체 b는 객체 a의 메모리 주소 값을 참조(= 공유)하지만 객체 a의 값을 변경할 방법이 없다.
→ 즉, 정의된 객체의 값을 변경할 수 있는 메서드가 존재하지 않는다.
3. 임베디드 타입(Embedded)
a) 개념
- 값 타입의 한 종류로, 기본 값 타입을 조합하여 새로운 값 타입을 정의하는 방식으로 사용하는 타입이다.
- 다른 이름으로 복합 값 타입이라고 부르기도 한다.
- 기본 값 타입뿐만 아니라, Entity와 함께 조합할 수도 있다.
- 즉, 공통된 속성을 묶어 클래스로 만든다는 것이 임베디드 타입의 핵심이다.
- 값 타입의 종류이므로, 임베디드 타입 또한 Entity의 생명주기에 종속적이다.
- JPA는 임베디드(Embedded) 타입이라고 말할 수 있다.
b) 추상화를 통한 클래스 생성
- 임베디드 타입은 쉽게 말해서 추상화를 통해 묶어낼 수 있는 기본 값 타입을 하나의 클래스로 만드는 것이다.
- 예를 들어, 회원은 다음과 같이 이름, 나이, 도시, 상세 주소, 우편번호를 가진다고 해보자.
public class Member {
String name;
int age;
String city;
String street;
String zipCode;
}
- 그러나 이를 추상화 하면, 회원은 개인 정보와 주소 정보를 가진다고 표현할 수 있다.
- 더불어, 추상화를 통해 묶은 속성 정보를 클래스로 다음과 같이 뽑아낼 수도 있다.
public class Member {
PersonalInfo info;
Address address;
}
- 이처럼 기본 값 타입을 클래스 단위로 묶어 추출하여 사용하는 것을 임베디드 타입이라고 한다.
c) 임베디드 타입을 사용하는 이유
- 임베디드 타입을 사용하면 코드의 재사용성이 증가한다.
→ 회원 객체는 개인 정보와 주소 정보를 포함하고 있기 때문이다.
- 특정 임베디드 타입을 고정적으로 사용하는 객체가 존재한다. 즉, 코드의 응집도가 증가한다.
ex) 회원 객체는 반드시 개인 정보와 주소 정보를 갖는다.
- 더불어, 임베디드 타입은 클래스의 형태로 구현되기 때문에 공통된 속성을 이용한 메서드를 구현할 수 있다.
ex) address.setCity(), address.setStreet();
d) @Embeddable ,@Embedded
- 임베디드 타입을 구현하는 방법에 대해서 알아보자.
- 임베디드 값 타입을 정의한 클래스에는 @Embeddable 어노테이션을 부착한다.
- 참고로, 임베디드 값 타입을 정의할 때에는 반드시 기본 생성자를 포함해야한다.
@Embeddable // 임베디드 값 타입을 정의한다는 어노테이션
public class Address {
private String city;
private String street;
private String zipcode;
public Address() {} // 기본 생성자 필수!!!
public Address(String city, String street, String zipcode) { // 일반 생성자
this.city = city;
this.street = street;
this.zipcode = zipcode;
}
// Getter & Setter 생략
}
- 임베디드 값 타입을 호출하여 사용하는 필드에는 @Embedded 어노테이션을 부착한다.
@Entity
public class Member extends BaseEntity {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
private String name;
@Embedded // 임베디드 값 타입을 사용한다는 어노테이션
private Address address;
// Getter & Setter 생략
}
e) 코드 실행
- 다음 코드를 사용해서 실행해보자.
- DB를 확인해보면 다음과 같이 값이 잘 들어간 것을 확인할 수 있다.
f) @AttributeOverrides, @AttributeOverride
- 만약 하나의 Entity안에서 동일한 임베디드 타입을 중복적으로 사용한다면 어떻게 될까?
- 예를 들어, 회원 객체가 2가지 주소(= 집 주소, 회사 주소)를 가진다면 어떻게 구현할까?
- 이때 사용할 수 있는 어노테이션이 @AttributeOverrides다.
- 다음 예시 코드를 통해 사용법을 익혀보자.
@Entity
public class Member extends BaseEntity {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
private String name;
@Embedded
private Address homeAddress;
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "city", column = @Column(name = "WORK_CITY")),
@AttributeOverride(name = "street", column = @Column(name = "WORK_STREET")),
@AttributeOverride(name = "zipcode", column = @Column(name = "WORK_ZIP")),})
private Address workAddress;
@OneToMany(mappedBy = "member")
private List<Order> order = new ArrayList<>();
// Getter & Setter 생략
}
- 위의 코드처럼, 중복된 칼럼 명을 일일이 재정의 해야한다.
- 다음 코드를 실행하면 쿼리 문과 DB를 통해 올바르게 칼럼이 들어간 것을 확인할 수 있다.
g) 결론
- 임베디드 타입은 Entity의 값일 뿐이다.
- 임베디드 타입을 사용하든 안 하든, 매핑하는 테이블은 동일하다.
- 다만, 객체와 테이블을 세밀하게 매핑하는 것이 가능하다는 장점이 있다.
- 더불어, 조금 더 객체지향스럽게 개발할 수 있다는 장점이 있다.
- 잘 설계한 ORM 애플리케이션은 이처럼 매핑한 테이블의 수보다 클래스의 수가 더 많다.
'Back-end > JPA 개념' 카테고리의 다른 글
20. 값 타입(3) - 객체 비교와 equals() 재정의 (0) | 2022.04.18 |
---|---|
19. 값 타입(2) - 문제점과 불변 객체 (0) | 2022.04.15 |
17. 고아 객체(Orphan) (0) | 2022.04.13 |
16. 영속성 전이(Cascade) (0) | 2022.04.12 |
15. 지연 로딩 & 즉시 로딩(N + 1 문제) (0) | 2022.04.11 |
댓글