값 타입

hyemin·2022년 2월 18일
0

JPA

목록 보기
7/7
post-thumbnail

JPA의 데이터 타입 분류

JPA의 데이터 단위는 최상위로 분류하면 두 가지로 분류한다.

  • 엔티티 타입
    • @Entity로 정의하는 객체
    • 데이터가 변해도 식별자로 지속해서 추적가능하다.
    • 예) 회원 엔티티의 키나 나이 값을 변경해도 키와 나이는 계속 식별자로 인식가능하다.
  • 값 타입
    • 쉽게 말해서 그냥 값으로 쓰이는 것들이다.
    • int, Integer,String처럼 단순히 값으로 사용하는 자바 기본 타입이나 객체이다.
    • 식별자가 없고 값만 있으므로 변경 시 추적이 불가능하다.
    • 예) 숫자 100을 200으로 변경하면 완전히 다른 값으로 대체되는 것이다.

값 타입

값 타입은 크게 3가지로 나누어 볼 수 있다.

값 타입 분류

  1. 기본 값 타입
    • 자바 기본 타입(int, double)
    • 래퍼 클래스(Integer, Long)
    • Stirng
  2. 임베디드 타입(embedded type, 복합 값 타입)
  3. 컬렉션 값 타입(colleciton value type)

기본 값 타입

String name, int age

위의 예시는 기본 값 타입이다.

  • 기본 값 타입은 생명주기를 엔티티에 의존한다.

    • 회원을 삭제하면 이름, 나이 필드도 함께 삭제된다. 이러한 기본 값 타입들은 회원 엔티티에 생명주기를 의존하고 있는 것이다.
  • 값 타입은 공유하면 안된다.

    • 회원 이름 변경 시 다른 회원의 이름도 변경되어서는 안된다.

int, double 등 자바의 기본 타입(primitive type)은 절대 공유하면 안된다.
기본 타입은 항상 값을 복사하지 공유되는 것이 아니다.

래퍼클래스나 String같은 클래스는 공유가 가능한 객체이지만 변경 자체가 불가능하다.

임베디드 타입

새로운 값 타입을 직접 정의할 수 있다.
이렇게 새롭게 정의하는 타입을 JPA는 임베디드 타입(Embedded type)이라고 한다.

  • 주로 기본 값 타입을 모아서 만들어서 복합 값 타입이라고도 한다.
  • int, String과 같은 값 타입이다.

    임베디드 타입은 엔티티가 아니라 값 타입이라는 것 주의하자.

임베디드 타입을 왜 사용할까?

  • 회원 엔티티가 있을 때
    회원엔티티는 '프로필 사진, 직업, 프로필 이미지, 한줄 설명, url을 가진다.'라고 하는 것 보다 '회원엔티티는 프로필을 가진다.'라고 설명하는 것이 더 정확하다.

회원이 상세한 데이터를 그대로 가지고 있는 것은 객체지향적이지 않으며 응집력만 떨어뜨린다.

// 임베디드 타입 사용하지 않았을 때
@Entity
public class Member {
  
  @Id @GeneratedValue
  private Long id;
  private String name;
  
  //프로필
  private String bio;
  private String uri;
  private String image;
  ....}
// 임베디드 타입 사용
@Entity
public class Member {
  
  @Id @GeneratedVAlue
  private Long id;
  private String name;
  
  @Embedded
  private Profile profile;	// 프로필
}

이렇게 프로필 타입이 있다면 코드가 더 명확해 진 것을 볼 수 있다.

임베디드 타입 사용법

  • @Embeddable을 값 타입을 정의하는 곳에 표시한다.
  • @Embedded을 값 타입을 사용하는 곳에 표시한다.
  • 기본 생성자가 필수이다.

임베디드 타입의 장점

  • 재사용성이 높고, 높은 응집도를 가지게 된다.
  • 해당 값 타입만이 사용하는 의미있는 메소드를 만들 수 있다.
  • 임베디드 타입을 포함한 모든 값 타입은, 값 타입을 소유한 엔티티에 새명주기를 의존한다.
    • 당연히 값 타입들은 엔티티가 사라지면 같이 사라진다.

임베디드 타입과 테이블 매핑

임베디드 타입은 엔티티의 값일 뿐이다.

  • 임베디드 타입을 사용하기 전과 후에 매핑하는 테이블은 같다.
  • 객체와 테이블을 아주 세밀하게 매핑하는 것이 가능하며, 모델링도 보다 깔끔하게 된다.
  • 잘 설계한 ORM 애플리케이션은 매핑한 테이블의 수 보다 클래스의 수가 더 많을 것이다.
  • 임베디드 타입의 값이 null인 경우에 매핑한 컬럼 값은 모두 null이다.

@AttributeOverride

@AttributeOverride : 속성 재정의

  • 한 엔티티에서 같은 값 타입을 사용하게 되면 컬럼 명이 중복되어서 에러가 발생한다.

이런 경우에 @AttributeOverrides와 @AttributeOverride를 사용해서 컬럼 명 속성을 재정의 할 수 있다.

  • 다만 이럴 경우 DB컬럼을 따로 매핑해야한다.

값 타입과 불변 객체

값 타입 공유 참조

임베디드 타입 같은 값 타입을 여러 엔티티에서 공유하면 위험하다.

  • 값 타입의 실제 인스턴스 값을 공유하게 되면, 어느 한 쪽에서 값을 변경하면 모두 다 변경되어 버리기 때문에 위험하다.
  • 대신 값(인스턴스)를 복사해서 사용하도록 하자.

하지만 임베디드 타입 처럼 직정 정의한 값은 자바의 기본 타입이 아닌 객체이다.
자바 기본 타입에 값을 대입하면 값을 복사하지만, 객체 타입은 참조 값을 직접 대입하는 것을 막을 수 없다.

객체의 공유 참조는 피할 수 없는 것이다.


//기본 타입(primitive type)
int a = 10;
int b = a; //기본 타입은 '값'을 복사
b = 4; //a에게는 아무 영향이 없다 a는 그대로 10

//하지만 객체 타입의 경우
Address a = new Address("Old");
Address b = a; //객체 타입이므로 참조를 전달한다.
b.setCity("newCity"); //a,b 둘다 바뀌게 된다. 같은 인스턴스를 공유하고 있기 때문에

그래서 객체 타입을 수정할 수 없게 값 타입은 불변 객체로 설계하도록 하자.

  • 불변객체란 생성 시점 이후 절대 값을 변경할 수 없는 객체이다.
  • 생성자로만 값을 설정할 수 있도록 하고 setter(수정자)를 만들지 않으면 된다.

참고로 Integer와 String은 자바가 제공하는 대표적인 불변 객체이다.

값 타입 컬렉션

값 타입을 하나 이상 저장할 때 사용한다.

  • 값 타입을 컬렉션에 담아 쓰는 것을 말한다.
  • @ElementCollection, @CollectionTable을 사용한다.
  • 데이터 베이스는 컬렉션을 같은 테이블에 저장할 수 없으므로, 컬렉션을 저장하기 위한 별도의 테이블이 필요하다.
  • 값 타입 컬렉션을 매핑하는 테이블은 모든 컬럼을 묶어서 기본 키를 구성해야한다.(null 입력 불가, 중복 저장 불가)

실무에서는 상황에 따라 값 타입 컬렉션 대신에 일대다 관계를 사용하는 것을 고려하자.
(일대다 관계를 위한 엔티티를 만들고, 여기에서 값타입을 사용)

값 타입 특징

  • 식별자 개념이 없다.
  • 생명주기를 엔티티에 의존한다.
  • 공유하지 않는 것이 안전하다.
  • 불변객체로 만들어서 사용하자.



Reference

https://www.inflearn.com/course/ORM-JPA-Basic/dashboard 김영한 님의 JPA 프로그래밍 강의
https://book.naver.com/bookdb/book_detail.nhn?bid=9252528 자바 ORM 표준 JPA 프로그래밍
위의 책을 참고하고, 강의를 수강하면서 작성한 글입니다.
틀린 부분 등 다양한 피드백 환영합니다.

profile
열심히 성장 중 :)

0개의 댓글