JPA의 데이터 타입 분류
엔티티 타입
- @Entity로 정의하는 객체
- 데이터가 변해도 식별자로 지속해서 추적 가능
- member 엔티티의 키나 나이 등 값을 변경해도 pk값으로 인식 가능
- 생명 주기를 관리한다.
값 타입
- int, Integer, String, LocalDateTime처럼 단순히 값으로 사용하는 자바의 기본 타입이나 객체
- 식별자(PK)가 없고 값만 있어서 값을 변경하면 추적이 불가능하다.
- lastModifiedDate를 now로 변경하면 완전히 다른 값으로 대체된다.
- 생명 주기를 엔티티에 의존한다. (엔티티의 생명주기를 따라간다)
- 공유하지 않는 것이 안전(객체면 불변객체로 해서 복사해 사용하자)
값 타입의 분류
기본값 타입
- 자바 기본 타입(int, double)
- 래퍼 클래스(Integer, Long)
- String
생명주기를 엔티티에 의존한다.
- 예) 회원을 삭제하면 이름, 나이 등 내부 필드들도 함께 삭제된다.
값 타입은 공유하면 안된다.
- 예) A 회원 이름을 변경했을 때 참조를 같은 인스턴스에 하고 있어서 B 회원 이름이 함께 변경되면 안된다.
- 자바의 기본 타입(primitive type - int, double...)은 절대 공유되지 않고 항상 값을 복사한다.
임베디드 타입 (embedded type, 복합 값 타입)
새로운 값 타입을 직접 정의할 수 있다.
JPA에서는 이 값 타입을 임베디드 타입이라고 한다.
기본 값 타입을 모아서 만들어져서 복합 값 타입이라고도 불린다.
기본 값 타입과 같은 범주의 "값 타입"이다.
실제 DB에는 나열되어 저장된 것 처럼 보이나 객체 단에서는 객체로 묶여있는 형태이다.
CITY, STREET, ZIPCODE를 묶어 ADDRESS라는 임베디드 타입 객체로 만들어도
DB에는 세개의 컬럼이 새로 생성된다는 이야기.
임베디드 타입의 사용법
- @Embeddable: 값 타입을 정의하는 곳에 표시
- @Embedded: 값 타입을 사용하는 곳에 표시
- 기본 생성자 필수
임베디드 타입의 장점
재사용이 가능하다.
높은 응집도를 가지고 있다.
해당 값 타입만 사용하는 의미있는 메소드를 만들 수 있다. -> Period.isWork()
임베디드 타입을 포함한 모든 값 타입은 값 타입을 소유한 엔티티에 생명주기를 의존한다.
-> 이게 무슨 말이냐면 Member 안에 Address가 있으면 Member를 Delete하면 Address도 Delete된다는 이야기다.
임베디드 타입과 테이블 매핑
임베디드 타입은 하나의 객체로 구성이 되어 있지만 별도의 엔티티가 아니다.
그저 값들의 모임일 뿐이다.
객체와 테이블을 아주 세밀하게(find-grained) 매핑하는 것이 가능하다.
잘 설계한 ORM 애플리케이션은 매핑한 테이블의 수보다 클래스의 수가 더 많다.
-> 진행중인 프로젝트에 녹여봐야 겠다.
임베디드 타입의 값이 null이면 매핑한 컬럼의 값은 모두 null이다.
불변객체
임베디드 타입 같은 값 타입(primitive 타입 X)을 여러 엔티티에서 공유하면 side effect가 발생할 수 있다.
서로 다른 인스턴스는 다른 값으로 인식해 ==을 인식하지 못하고
=을 통해 하나의 인스턴스를 다른 곳에 대입시키면 같은 참조값을 가져
한 인스턴스의 값을 바꾸면 다른 인스턴스 값까지 바뀌는 예측 불가능한 상황이 발생한다.
따라서 인스턴스끼리의 값 복제가 하고싶다면
완전히 새로운 인스턴스를 만들어 기존 값(정말 값만)들만 새로 넣어줘야 한다.
그러면 한 인스턴스에 대한 값에 대한 변경을 막아버리면 어떻게 될까?
한번 인스턴스가 만들어지면 그 인스턴스의 값은 변경하지 못하게 막아버리면?
그러면 값 복제를 하기 위해서는 무조건적으로 새로운 인스턴스를 만들어야 할 것이다.
이를 위해 불변 객체(immutable object) 라는 개념이 탄생했다.
Integer, String은 대표적인 자바의 불변 객체이다.
setValue()같은 메소드가 없고 적용도 안되기 때문이다.
즉, 수정자(Setter)가 없으면 불변 객체가 될 수 있다.
작은 제약으로 부작용이라는 재앙을 막을 수 있다.
이제 왜 객체를 만들 때 Setter는 빼고 만들라는지 알겠는가?
값 타입의 비교
동일성(identity) 비교 -> 인스턴스의 참조값을 비교, == 사용한다.
동등성(equivalence) 비교 -> 인스턴스의 값을 비교, equals()를 오버라이딩해 비교한다.
컬렉션 값 타입 (collection value type)
Set<String> 처럼 말 그대로 컬렉션을 사용하는 값 타입이다.
엔티티 내부에 컬렉션을 사용한 컬럼이 있는 것이다.
이 값 타입은 문제가 많다.
엔티티와 다르게 식별자의 개념이 없어 한번 값을 변경하면 그 값을 다시 찾아내기가 어렵다.
모든 컬럼을 묶어서 기본키를 구성한다. -> null 허용 불가, 중복 저장 불가
이러한 이유들이 있어 실무에서는 일대다 관계를 선호한다고 한다.
값 타입 컬렉션처럼 사용하고 싶다면 영속성 전이(Cascade) + 고아 객체 제거를 사용해 구현한다.
그렇게하면 매핑되는 테이블과 관리 및 생명주기가 같아지기 때문이다.
이번 챕터에서는 임베디드 타입에 대해 안 것이 좋았다.
지금 진행중인 프로젝트의 엔티티 구조를 임베디드 타입으로 리팩토링 해야겠다.
'Spring > 이론' 카테고리의 다른 글
[JPA] JPQL 경로 표현식 (0) | 2023.08.02 |
---|---|
[JPA] JPQL 문법과 기능 (0) | 2023.07.26 |
Spring Security 동작 원리 / 필터 순서 (0) | 2023.07.05 |
JPA - 영속성 전이, 고아 객체 (0) | 2023.06.29 |
JPA 기본 - 지연 로딩 즉시 로딩 (0) | 2023.06.28 |