[JPA] 값 타입

gyeol·2024년 8월 6일

JPA

목록 보기
9/13
post-thumbnail

김영한 님의 '자바 ORM 표준 JPA 프로그래밍 - 기본편'를 듣고 적은 글 입니다.

JPA의 데이터 타입 분류

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

  • 값 타입
    int, Integer 처럼 단순히 값으로 사용하는 자바 기본 타입이나 객체로 식별자가 없고 값만 있으므로 변경시 추적할 수 없다.

값 타입

  • 기본값 타입 : 자바 기본 타입(int, double), 래퍼 클래스(Integer, Long), String

  • 임베디드 타입

  • 컬렉션 값 타입

기본 값 타입

생명 주기를 엔티티에 의존하며 값 타입은 공유하면 안된다.
기본 타입은 항상 값을 복사한다. side effect가 일어나면 안되기 때문이다. 값은 복사되기 때문에

int a=10;
int b=a;

a=20;

이렇게 해서 a와 b를 출력했을 때 b의 값은 바뀌지 않는다.

임베디드 타입

새로운 값 타입을 직접 정의할 수 있다. JPA는 임베디드 타입이라고 한다.
주로 기본 값 타입을 모아 만들어서 복합값 타입이라고도 한다.

이와 같이 우리가 Period, Address 타입을 만들어 사용할 수 있다. 그 안에는 기본 값 타입들이 사용되고 있음을 확인할 수 있다.

사용법

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

장점

  • 재사용성이 높다.
  • 해당 값 타입만 사용하는 의미있는 메소드를 만들 수 있다.
  • 임베디드 타입을 포함한 모든 값 타입은 값 타입을 소유한 엔티티에 생명 주기를 의존한다.

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

  • 임베디드 타입은 엔티티의 값일 뿐이다.
  • 임베디드 타입을 사용하기 전과 후에 매핑하는 테이블은 같다. 결국 임베디드 타입 안에서 사용하는 타입은 기본 값 타입이기 때문이다. 우리는 새롭게 만든 임베디드 타입을 테이블에 매핑만 잘해주면 된다.
  • 객체와 테이블을 아주 세밀하게 매핑하는 것이 가능하다.

@AttributeOverride

한 엔티티에서 같은 값 타입을 사용하면 컬럼명이 중복되는데 이때 @AttributeOverrides, @AttributeOverride를 사용해서 컬럼 명 속성을 재정의 해줄 수 있다.

임베디드 타입과 null

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

값 타입과 불변 객체

임베디드 타입같은 값 타입을 여러 엔티티에서 공유하면 위험하다. 왜냐! side effect가 발생할 수 있기 때문이다.

//Member 객체가 있다고 가정하자...

Member m1 = new Member("aa", "oldcity");
Member m2 = m1;

m2.setAddress("newCity");

이렇게 m2의 주소를 변경하면 m1의 주소도 변경되는 것을 확인할 수 있따. 값 타입의 실제 인스턴스인 값을 공유하는 것은 위험하다. 그래서 우리는 값을 복사해서 사용해야 한다.

객체 타입의 한계

  • 항상 값을 복사해 사용하면 공유참조로 인해 발생하는 부작용을 피할 수 있다.
  • 문제는 임베디드 타입처럼 직접 정의한 값 타입은 자바 기본 타입이 아닌 객체 타입이기에 참조 값을 직접 대입하게 된다.
  • 자바 기본 타입에 값을 대입하면 값을 복사한다.
  • 객체의 공유 참조는 피할 수 없다 !!!
// 기본 타입
int a = 10;
int b = a;
b = 4; //b의 값만 변경 됨

//객체 타입
Address a = new Address("old");
Address b = a;
b.setCity("New"); //a와 b 모두 변경 됨

불변 객체

객체 타입을 수정할 수 없게 만들면 부작용의 원천을 차단할 수 있다. 그렇기에 우리는 불변 객체로 설계해야 한다. 생성자로만 값을 설정하고 설정자를 만들지 않으면 된다. 생성자를 private로 설계해줘도 된다.

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

값 타입의 비교

기본 타입의 경우 ==로 비교하면 되지만 객체 타입의 경우 equals() 메서드를 사용해 비교해야 한다. 객체 타입을 ==로 비교할 경우 결과는 항상 false가 나온다.

값 타입 컬렉션

값 타입 컬렉션은 값 타입을 하나 이상 저장할 때 사용하며 데이터베이스는 컬렉션을 같은 테이블에 저장할 수 없기에 컬렉션을 저장하기 위한 별도의 테이블을 만들어야 한다. 즉, 일대다 연관관계를 가진다.
이때 값 타입 컬렉션 변수를 사용할 때에는 @ElementCollection, @CollectionTable 애노테이션을 사용하면 된다.

값 타입 컬렉션은 지연 로딩 전략을 사용한다는 점을 명심하자 !

값 타입 컬렉션의 제약사항

  • 값 타입은 엔티티와 다르게 식별자 개념이 없다.
  • 값은 변경하면 추적이 어렵다. 데이터베이스에 생성되는 테이블 구조를 보면 그 값을 추적할 수 있는 컬럼이 존재하지 않기 때문이다. 이때 값을 변경할 때 새롭게 객체를 생성해야 한다.
  • 값 타입 컬렉션에 변경사항이 발생하면, 주인 엔티티와 연관된 모든 데이터를 삭제하고 값 타입 컬렉션에 있는 현재 값을 모두 다시 저장한다.
  • 값 타입 컬렉션을 매핑하는 테이블은 모든 칼럼을 묶어서 기본 키를 구성해야 한다. null을 입력하면 안되고 중복저장도 안된다 !!

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

profile
공부 기록 공간 '◡'

0개의 댓글