개발/JPA

값 타임

Debin 2022. 3. 3.
반응형

2023. 02.07 17:00 복습 및 정리 시작

 

JPA는 데이터 타입을 크게 두 분류로 나눌 수 있다.

엔티티 타입

@Entity로 정의하는 객체다. 데이터가 변해도 식별자로 지속해서 추적이 가능하다.

회원 엔티티의 키나 나이 값을 변경해도 식별자로 인식 가능하다. 

값 타입

int, Integer, String처럼 단순히 값으로 사용하는 자바 기본 타입이나 객체다.

숫자 100을 200으로 변경하면 완전히 다른 값으로 대체된다.

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

 

  • 기본 값 타입 : 자바 기본 타입, 래퍼 클래스, String
  • 임베디드 타입 : 복합 값 타입
  • 컬렉션 값 타입 

이제 차근 차근 알아보겠다. 우선 아래 예제 코드를 살펴보자.

@Entity
public class Member{
    @Id @GeneratedValue
    private Long id;
    
    private String name;
    private int age;
    
    //주소
    private String city;
    private String street;
    private String zipcode;
}

기본 값 타입

  • 위 코드에서는 String name, int age 변수가 기본 값 타입이다.
  • 생명주기를 엔티티에 의존한다. 
  • 값 타입은 공유하면 안 된다. 
  • 다른 회원 엔티티의 이름을 변경한다고 해서 나의 이름까지 변경되는 것은 잘못되었기 때문이다.

임베디드 타입

위 예제 코드에서 주소를 나타내는 필드들이 있다.

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

이제 새로운 값 타입을 직접 정의해서 사용하는 임베디드 타입을 사용해보겠다.

@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;
    private int age;
    
    @Embedded Address homeAddress; //집 주소
}

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

  • 새로운 값 타입을 직접 정의할 수 있다.
  • 주로 기본 값 타입을 모아서 복합 값 타입이라고 한다. int, String과 같은 값 타입.
  • @Embeddable : 값 타입을 정의하는 곳에 표시
  • @Embedded : 값 타입을 사용하는 곳에 표시
  • 기본 생성자는 필수다.

장점

  • 재사용을 자주하며 높은 응집도를 가지게 된다.
  • 해당 값 타입만 사용하는 의미 있는 메소드를 만들 수 있다.
  • 임베디드 타입을 포함한 모든 값 타입은, 값 타입을 소유한 엔티티에 생명주기를 의존한다.

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

  • 임베디드 타입은 엔티티의 값일 뿐이다.
  • 임베디드 타입을 사용하기 전과 후에 매핑하는 테이블은 같다.
  • 객체와 테이블을 아주 세밀하기 매핑하는 것이 가능하다.
  • 잘 설계한 ORM 애플리케이션은 매핑한 테이블의 수보다 클래스의 수가 더 많다.
  • 임베디드 타입에 정의한 매핑정보를 재정의하려면 엔티티에 @AttributeOverride를 사용하면 된다.
  • 임베디드 타입의 값이 null이면 매핑한 컬럼 값은 모두 null이다.

값 타입과 불변 객체

값 타입은 복잡한 객체 사상을 조금이라도 단순화하려고 만든 개념이다.

따라서 값 타입은 단순하고 안전하게 다룰 수 있어야 한다.

임베디드 타입 값 타입을 여러 엔티티에서 공유하면 위험하다. 부작용이 발생할 수도 있다.

아래와 같은 예시가 있을 수 있겠다.

값 타입 공유 참조

값 타입의 실제 인스턴스인 값을 공유하는 것은  매우 위험하다.

따라서 값을 복사해서 사용하자.

 

항상 값을 복사해서 사용하면 공유 참조로 인해 발생하는 부작용을 피할 수 있지만,

문제는 임베디드 타입처럼 직접 정의한 값 타입은 자바의 기본 타입이 아니라 객체 타입이다. 즉 주소를 참조한다.

자바 기본 타입에 값을 대입하면 값을 복사하지만, 객체 타입은 참조 값을 직접 대입하는 것을 막을 방법이 없다.

따라서 객체의 공유 참조는 피할 수 없다.

불변 객체

값 타입은 부작용 걱정 없이 사용할 수 있어야 한다. 부작용이 일어나면 값 타입이라 할 수 없다.

객체를 불변하게 만들면 값을 수정할 수 없으므로 부작용을 원천 차단할 수 있다. 따라서 값 타입을 될 수 있으면 불변 객체로 설계해야 한다.

불변 객체를 구현하는 다양한 방법이 있지만 가장 간단한 방법은 생성자로만 값을 설정하고 수정자를 만들지 않으면 된다.

이러면 불변이라는 작은 제약으로 부작용이라는 큰 재앙을 막을 수 있다.

Integer, String은 자바가 제공하는 대표적인 불변 객체다.

값 타입 비교

값 타입은 인스턴스가 달라도 그 안에 값이 같으면 같은 것으로 봐야 한다.

 

  • 동일성 비교 : 인스턴스의 참조 값을 비교, == 사용
  • 동등성 비교 : 인스턴스의 값을 비교, equals() 사용
  • 값 타입은 a.equals(b)를 사용해서 동등성 비교를 해야 함
  • 값 타입의 equals() 메소드를 적절하게 제정의(오버 라이딩)해서 사용하자.

값 타입 컬렉션

아래는 임베디드 타입을 하나 이상 가지고 싶어서 컬렉션에 보관한 케이스다.

값 타입 컬렉션

@ElementCollection@CollectionTable를 사용하면 값 타입 하나 이상을 컬렉션에 저장할 수 있다.

데이터베이스는 컬렉션을 같은 테이블에 저장할 수 없으며, 컬렉션을 저장하기 위한 별도의 테이블이 생긴다.

값 타입 컬렉션도 지연 로딩 전략을 기본으로 사용하며, 영속성 전이와 고아 객체 제거 기능을 필수로 가진다고 볼 수 있다.

 

값 타입 컬렉션의 제약사항은 아래와 같다.

 

  • 값 타입은 엔티티와 다르게 식별자 개념이 없다.
  • 값은 변경하면 추적이 어렵다.
  • 값 타입 컬렉션에 변경 사항이 발생하면, 주인 엔티티와 연관된 모든 데이터를 삭제하고,
    값 타입 컬렉션에 있는 현재 값을 모두 다시 저장한다.
  • 값 타입 컬렉션을 매핑하는 테이블은 모든 컬럼을 묶어서 기본키를 구성해야 한다. null 입력 X, 중복 저장 X.

이런 제약사항이 있으므로 실무에서는 상황에 따라 값 타입 컬렉션 대신에 일대다 관계를 고려해야 한다고 한다.

일대다 관계를 위한 엔티티를 만들고, 여기에서 값 타입을 사용한다.

영속성 전이 + 고아 객체 제거를 사용해서 값 타입 컬렉션처럼 사용한다.

정리

  • 값 타입은 정말 값 타입이라 판단될 때만 사용해야 한다.
  • 엔티티와 값 타입을 혼동해서 엔티티를 값 타입으로 만들면 안 된다.
  • 식별자가 필요하고, 지속해서 값을 추적, 변경해야 한다면 그것은 값 타입이 아닌 엔티티다.

 

참고자료

 

자바 ORM 표준 JPA 프로그래밍 - 김영한

자바 ORM 표준 JPA 프로그래밍 강의 - https://www.inflearn.com/course/ORM-JPA-Basic/dashboard

 

자바 ORM 표준 JPA 프로그래밍 - 기본편 - 인프런 | 강의

JPA를 처음 접하거나, 실무에서 JPA를 사용하지만 기본 이론이 부족하신 분들이 JPA의 기본 이론을 탄탄하게 학습해서 초보자도 실무에서 자신있게 JPA를 사용할 수 있습니다., - 강의 소개 | 인프런

www.inflearn.com

 

2023. 02.07 17:40 복습 및 정리 마무리

 
반응형

댓글