과정을 즐기자

값 타입 본문

Spring Data

값 타입

320Hwany 2022. 12. 11. 21:26

JPA의 데이터 타입

JPA의 데이터 타입을 가장 크게 분류하면 엔티티 타입과 값 타입으로 나눌 수 있다.

엔티티 타입의 특징

  1. 식별자(@Id)가 있어 식별자로 구분할 수 있다.
  2. 생성하고 영속화하고 소멸하는 생명주기가 있다.
  3. 어떤 한 엔티티가 다른 엔티티에서 얼마든지 참조될 수 있다. 즉 참조 값을 공유할 수 있다.

값 타입의 특징

  1. 식별자가 없다
  2. 생명 주기가 엔티티에 의존한다.
  3. 오직 하나의 주인만이 관리하게 해야하며 불변 객체로 만들고 공유하지 않는 것이 안전하다.

이제 값 타입에 대해서 더 자세히 알아보자

값 타입

값 타입은 3가지로 나눌 수 있다.

  1. 기본 값 타입
  2. 임베디드 타입
  3. 컬렉션 값 타입

기본 값 타입

기본 값 타입에는 자바 기본 타입, 래퍼 클래스, String이 있다. 이들은 위에서 말한 것 처럼 생명주기가 엔티티에 의존한다.
또한 값 타입은 공유하면 안된다.

임베디드 타입(복합 값 타입)

새로운 값 타입을 직접 정의해서 사용할 수 있는데 JPA에서는 이것을 임베디드 타입이라고 한다.
임베디드 타입도 값 타입이라고 할 수 있다.

예를들어 주소정보에는 도, 시, 구, ... 이렇게 계속 이어진다. 이러한 데이터를 모두 엔티티가 가지고 있다면 이것은 객체지향적이지 않고
응집력을 떨어뜨린다. 이러한 데이터들을 모아서 한번에 처리하여 주소라고 표현하는 것이 훨씬 더 좋은 방법일 것이다.
이러한 경우에 임베디드 타입을 만든다.

임베디드 타입을 만들기 위해서는 주소정보를 가지고 있는 Address 객체를 하나 만들자. 그리고 이 객체에 @Embeddble을 작성하자. (엔티티가 아니다)
그리고 엔티티에는 @Embedded라는 어노테이션을 필드에 적은 Address 앞에 붙여주자.

@Entity
public class Member {
      ...

     @Embedded Address address;
}
@Embeddable
public class Address {

    private String do;
    private String si;
    private String gu;
    ...
}

이렇게 만들면 훨씬 응집력있게 변한 것을 알 수 있다.

임베디드 타입은 값 타입이고 엔티티가 아니기 때문에 임베디드 타입을 사용하기 전과 후에 매핑하는 테이블은 같다.
잘 설계한 ORM 애플리케이션은 매핑한 테이블의 수보다 클래스의 수가 더 많다는 것을 알 수 있다.

값 타입 컬렉션

관계형 데이터베이스의 테이블은 컬럼 안에 컬렉션을 포함할 수 없다. 따라서 별도의 테이블을 추가하여 매핑해야 한다.
이때 @ElementCollection, @CollectionTable을 이용하여 값 타입 컬렉션을 사용할 수 있다.
이렇게 만든 값 타입 켈력션은 영속성 전이, 고아 객체 제거 기능을 가지고 있어 참조하는 테이블에 의존한다.
또한 조회할 때 지연 로딩으로 모두 설정되어 있다.

값 타입 컬렉션의 한계

하지만 엔티티는 식별자가 있으므로 값을 변경해도 식별자로 구분할 수 있는데 값 타입은 값을 변경해버리면 데이터베이스에 저장된
원본 데이터를 찾기 어렵다. 이러한 문제로 JPA 구현체들은 값 타입 컬렉션에 변경 사항이 발생하면 값 타입 컬렉션이 매핑된
테이블의 모든 데이터를 삭제하고 현재 값 타입 컬렉션 객체에 있는 모든 값을 데이터베이스에 다시 저장한다. (비효율적이다)

따라서 실무에서는 값 타입 컬렉션 대신에 엔티티로 만들어 일대다 관계로 매핑을 하도록 하자.

정리

값 타입은 정말 값 타입이라고 판단될 때만 사용해야한다. 식별자가 필요하고 지속해서 값을 추적하고 구분하고 변경해야 한다면
그것은 값 타입이 아닌 엔티티로 만들어야 한다.

출처 : 자바 ORM 표준 JPA 프로그래밍 (김영한)