가자공부하러!

Hibernate(7) - 값 타입 본문

공부/Java

Hibernate(7) - 값 타입

오피스엑소더스 2019. 11. 22. 14:35

1. JPA의 데이터 타입 분류

1.1. 엔티티 타입

  - @Entity로 정의하는 객체

  - 데이터가 변해도 식별자로 지속해서 추적 가능 ex) 회원 나이를 변경해도 식별자로 추적 가능

1.2. 값 타입

  - int, Integer, String 처럼 단순히 값으로 사용하는 자바 기본 자료형이나 객체

  - 식별자가 없고 값만 있으므로 변경 시 추적 불가 ex) 회원 나이를 20에서 21로 변경하면 완전히 다른 값으로 대체

  - 분류

    > 기본값 타입 : primprimative type, Wrapper Class, String

    > 임베디드 타입 : embedded type, 복합 값 타입

    > 컬렉션 값 타입

 

2. 타입 별 특징

2.1. 기본 값 타입

  - 생명주기를 엔티티에 의존

  - 값타입이 공유되어서는 안된다. ex) 회원A의 나이를 수정했을 때, 회원B의 나이가 수정되어서는 안된다.

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

  - 여러 엔티티에서 공유하면 부작용(side effect)이 발생할 확률이 높으므로 지양

    > 값을 복사해서 사용하도록

    > 불변객체로 설계하면 부작용을 차단할 수 있음

      - 생성자로만 값을 설정하고, 수정자(Setter)를 만들지 않으면 됨

  - 값 타입을 소유한 엔티티에 생명 주기를 의존함

  - 새로이 정의한 값 타입

  - 주로 기본 값 타입을 모아 만들기 때문에 복합 값 타입이라고도 함

  - 엔티티가 아니기 때문에 추적할 수 없다.

  - 객체와 테이블을 아주 세밀하게 매핑할 수 있다.

  - 사용 방법

    > 기본 생성자 필수

    > @Embeddable : 값 타입을 정의하는 곳에 표시

    > @Embedded  : 값 타입을 사용하는 곳에 표시

  - 한 엔티티에서 같은 값 타입을 두 번 이상 사용하면 컬럼 명이 중복됨

    > @AttributeOverride, @AttributeOverrides 활용

  - 임베디드 타입 변수 자체가 null이면 임베디드 타입이 갖는 모든 변수는 null

package jpql;

import lombok.Getter;
import javax.persistence.Embeddable;

@Embeddable
@Getter
public class Address {
    private String city;
    private String street;
    private String zipcode;
}
package jpql;

import lombok.Getter;
import lombok.Setter;

import javax.persistence.*;

@Entity
@Table(name = "ORDERS")
@Getter @Setter
public class Order {

    @Id @GeneratedValue
    private Long id;
    private int orderAmount;

    @Embedded
    private Address address;

    @ManyToOne
    @JoinColumn(name = "PRODUCT_ID")
    private Product product;
}

 

3. 값 타입의 비교

3.1. 동일성(identity) 비교 : 인스턴스의 참조 값을 비교

  - == 사용

3.2. 동등성(equivalence) 비교 : 인스턴스가 갖는 값들을 비교

  - equals()와 hashCode() 메소드를 적절히 오버라이딩 해서 사용

  - equals() 오버라이딩에는 주로 모든 필드 사용

 

4. 값 타입 컬렉션

4.1. 엔티티가 컬렉션 변수를 가질 때(List, Set)

  - DB에서 각 컬렉션 변수는 각각의 테이블을 갖는다

  - @ElementCollection, @CollectionTable 사용

4.2. 값 타입 컬렉션 활용

  - 수정 쪽 문제 때문에 값 타입 컬렉션 대신에 일대다 관계를 활용하는게 이득

    > Cascade + 고아 객체 제거 기능을 사용해서 값 타입 컬렉션처럼 사용

    > 값 타입(Address.java)을 엔티티(AddressEntity.java)로 승급

//값 타입 컬렉션 대신에 엔티티 일대다 관계 활용
@OneToMany(orphanRemoval = true, cascade = CascadeType.ALL)
@JoinColumn(name = "MEMBER_ID")
private List<AddressEntity> addressHistory = new ArrayList<>();

  - 저장

    > 영속상태인 엔티티가 갖는 컬렉션에 add하고 커밋하면 끝 

  - 조회

    > 엔티티를 조회할 때는 컬렉션 값을 제외한 엔티티 내용만 가져옴

      - 컬렉션 값은 사용될 때 쿼리 수행됨 (지연 로딩)

  - 수정

    > 수정 대상을 삭제(remove)하고 새(new) 값을 add

      - 이렇게 하면 컬렉션 사이즈 만큼 딜리트, 인서트 쿼리가 수행됨

        - 값 타입 컬렉션에 변겨여 사항이 발생하면, 주인 엔티티와 연관된 모든 데이터를 삭제하고, 값 타입 컬렉션에 있는 현재 값을 모두 다시 저장한다. 값 타입에는 식별자 개념이 없고 추적이 어렵기 때문

      - 아주 위험하다.

4.3. 참고

  - 값 타입 컬렉션은 영속성 전이(Cascade) + 고아 객체 제거 기능을 필수로 가진다고 볼 수 있다.

    > 엔티티가 갖는 컬렉션의 생명주기는 엔티티에 종속되어 있기 때문

 

 

 

Comments