본문 바로가기

JPA

JPA - 값 타입

포스팅은 김영한님의 자바 ORM 표준 JPA 프로그래밍 책 내용을 기반으로 작성되었습니다.

 

JPA의 데이터 타입은 엔티티 타입과 값 타입으로 나눌 수 있습니다. 엔티티 타입은 @Entity로 정의하고 값 타입은 int, String 처럼 단순히 값으로 사용하는 자바 기본 타입이나 객체를 말합니다.

 

엔티티 타입은 식별자를 통해 지속해서 추적할 수 있지만, 값 타입은 식별자가 없고 숫자, 문자같은 속성만 있으므로 추적할 수 없습니다.

 

값 타입은 다음 3가지로 나눌 수 있습니다. 기본 값 타입, 임베디드 타입, 컬렉션 값 타입

목차

  • 기본값 타입
  • 임베디드 타입
  • 값 타입과 불변 객체 ★
  • 값 타입의 비교
  • 값 타입 컬렉션 ★

기본값 타입

MemberV1의 username, age가 값 타입이다.

 

MemberV1 엔티티는 id라는 식별자 값도 가지고 생명주기가 존재한다. 하지만 username, age 속성은 식별자 값도 없고 새명주기도 회원 엔티티에 의존한다. 회원 엔티티 인스턴스를 제거하면 username, age 도 함께 제거되는 것이 그 증거 중 하나이다.

 

그리고 값 타입은 공유하면 안 된다. 다른 회원 엔티티의 이름을 변경한다고 해서 내 이름까지 변경되는 것은 의도하지 않았기 때문이다.

 


임베디드 타입

새로운 값 타입을 직접 정의해서 사용할 수 있다. 이를 JPA에서는 임베디드 타입이라고 한다. 중요한 것은 직접 정의한 임베디드 타입도 int, String 처럼 값 타입이라는 것입니다.

 

 

스터디 엔티티는 스터디 이름, 카테고리, 컨텐츠, 저자, 이미지를 가진다. 이를 값 타입을 사용해서 개선해보겠습니다.

 

스터디는 이름과 주제를 가진다.

 

임베디드 타입을 이용하면 응집도가 올라가고 코드가 더 명확집니다. 그리고 임베디드 타입을 통해 메서드를 가질 수 있기 때문에 더 객체지향적라고 말합니다.

 

  • @Embeddable : 값 타입을 정의하는 곳에 표시
  • @Embedded : 값 타입을 사용하는 곳에 표시

 

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

임베디드 타입을 사용 전, 후 테이블 매핑의 차이는 없다. 하지만 객체 관점에서 봤을 때는 더 객체지향적으로 만들어진 것입니다.

 

임베디드 타입과 연관관계

엔티티는 공유될 수 있으므로 참조한다고 표현하지만, 값 타입은 특정 주인에 소속되고 논리적인 개념상 공유되지 않으므로 포함된다고 표현합니다.

 

 

값 타입은 값 타입, 엔티티 타입을 모두 가질 수 있습니다.

 

임베디드 타입과 null

임베디드 타입이 null이면 매핑한 컬럼 값은 모두 null 이다.

 

topic 임베디드 타입이 가지는 컬럼들이 모두 null이라는 의미이다.

 


값 타입과 불변 객체

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

 

값 타입 공유 참조

값 타입은 여러 엔티티에서 공유하면 위험하다. 아래와 같은 결과가 나올 수 있다.

 

 

study2의 category 컬럼만 변경되길 원했지만 둘다 변하게 된다. 기본 타입(int, String 등)이 아닌 객체는 참조 값을 전달하게 때문이다.

 

객체의 공유 참조는 피할 수 없습니다. 그래서 값 타입은 최대한 불변 객체로 만들어야 합니다. 만약 수정자가 필요하다면 생성자를 통해 수정하는 것을 권장한다. (이 내용은 도메인 주도 개발 시작하기, 최범균)을 참고한 내용입니다.

 

 


값 타입의 비교

 

자바가 제공하는 객체 비교는 2가지 입니다.

  • 동일성 비교  ==  사용
  • 동등성 비교  equals() 사용

값 타입은 일반적으로 인스턴스가 달라도 그 안에 값이 같으면 같은 것으로 봐야한다. 그래서 equals 를 사용하는 것을 권장한다. 자바 IDE에서는 대부분 equals, hashCode 메소드 자동 생성 기능이 있으니 이를 활용하자.

 

hashCode() 도 함께 재정의해야하는 이유는 해시를 사용하는 컬렉션 사용 시 사이드 이펙트를 없애기 위함이다.


값 타입 컬렉션

@ElementCollection, @CollectionTable 을 통해 만든다. 마치 1:N 연관 관계를 나타내는 테이블이 생성된다.

 

 

joinColumns 을 통해 외래키를 지정할 수 있다.

 

 

 

중요한 것은 값 타입 컬렉션은 영속성 전이 + 고아 객체 제거 기능을 필수로 가진다. 즉 엔티티가 삭제되면 값 타입 컬렉션도 함께 삭제된다.두 번째는 값 타입 컬렉션에서도 N + 1이 발생할 수 있다는 것이다. 참고로 값 타입 컬렉션 글로벌 패치 전략 디폴트는 LAZY다.