| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 |
- MSA
- dockerhub
- Spring
- Dead Letter Queue
- Spring Container
- 지연 로딩
- docker compose
- Spring Data JPA
- JWT
- redis
- 컨테이너
- Web
- securitycontextholderfilter
- @ComponentScan
- @Transactional
- AWS
- 서블릿 컨테이너
- JPA
- DLQ
- 페이징
- 스프링 부트
- mybatis
- Routing Key
- JPQL
- kafka
- DI
- 쿠버네티스
- JdbcTemplate
- docker
- CORS
- Today
- Total
look-forest
값 타입 본문
JPA의 데이터 타입 분류
- 엔티티 타입
- 식별자O (데이터가 변해도 식별자로 지속해서 추적 가능)
- 생명 주기 관리
- 공유
- 값 타입
- int, Integer, String처럼 단순히 값으로 사용하는 자바 기본 타입이나 객체
- 식별자X (고유 식별자가 없고 값만 있으므로 변경시 추적 불가)
- 생명 주기를 엔티티에 의존
- 공유하지 않는 것이 안전(복사해서 사용 or 참조 타입일 경우 불변 객체로)
값 타입은 정말 값 타입이라 판단될 때만 사용. 엔티티와 값 타입을 혼동해서 엔티티를 값 타입으로 만들면 안됨.
식별자가 필요하고, 지속해서 값을 추적, 변경해야 한다면 그것은 값 타입이 아닌 엔티티
값 타입을 사용하면 도메인을 모델링하기에 용이하고, (용어 정의가 되니까)
validation rule을 한 곳에서 모아서 관리할 수 있고 편의 메서드도 생성 가능해서 좀 더 객체지향적이다.
값 타입 분류
- 기본 값 타입 - 기본 타입은 값을 복사하므로 공유되지 않음. 래퍼, String은 공유 가능하지만 변경 불가.
- 임베디드 타입(embedded type, 복합 값 타입) - 좌표, 주소 등 새로운 값 타입을 직접 정의할 수 있음. '값'들의 묶음.
- 컬렉션 값 타입(collection value type) - 기본값, 임베디트 타입 등을 저장한 컬렉션

임베디드 타입 사용법
- @Embeddable: 값 타입을 정의하는 곳에 표시.
- @Embedded: 값 타입을 사용하는 곳에 표시


한 엔티티에서 같은 값 타입을 사용하면 컬럼 명이 중복된다.
@AttributeOverrides, @AttributeOverride를 사용해서 컬러 명 속성을 재정의하면 된다.
참고로 임베디드 타입은 속성으로 엔티티를 가질 수 있다.

값 타입과 불변 객체
값 객체의 가치 => 복잡성을 낮춰줌. 단순함
- 값 타입은 복잡한 객체 세상을 조금이라도 단순화하려고 만든 개념이다. 따라서 값 타입은 단순하고 안전하게 다룰 수 있어야 한다. -> 그래서 래퍼 클래스나 String은 불변으로 만든 것이다.
- 객체를 추적할 필요없이 값만 같으면 동일한 객체. (ex.같은 지폐일 필요는 없고 같은 액수면 된다)
=> 값 객체가 트래킹할 필요도 없고 복잡성을 낮춰줘서 단순하고 간편하다. - Primitive 타입의 개념을 명시적으로 드러내서 복잡성을 감소시키기 위해 사용
- 참조 객체에서 복잡하거나 중복되는 코드 그룹을 값 객체로 이동하기 위해 사용
값 타입 공유 참조
임베디드 타입 같은 값 타입을 여러 엔티티에서 공유하면 위험하다. (고유 식별자가 없어서 추적이 안됨)
대신 값(인스턴스)은 복사해서 사용해야 한다.

객체 타입을 수정할 수 없게 만들면 부작용을 원천 차단할 수 있다. (setter x)
값 타입은 불변 객체(immutable object)로 설계해야 한다. (생성 시점 이후 절대 값을 변경할 수 없는 객체)
불변이라는 작은 제약으로 부작용이라는 큰 재앙을 막을 수 있다.
+ 값은 변경하는게 아니고 새로 갈아끼워야 한다. "string1" -> "string2"는 값이 변경됐다기 보다는 갈아끼워진 것이다.

값 타입의 비교
값 타입은 인스턴스가 달라도 그 안에 값이 같으면 같은 것으로 봐야 한다. 값이니까.
따라서 값 타입은 a.equals(b)를 사용해서 동등성 비교를 해야 한다. (값 타입의 equals() 메소드를 적절하게 재정의)
- 동일성(identity) 비교: 인스턴스의 참조 값을 비교, == 사용
- 동등성(equivalence) 비교: 인스턴스의 값을 비교, equals() 사용
값 타입 컬렉션 (@ElementCollection)
값 타입을 하나 이상 저장할 때 사용 . List<엔티티> 처럼 엔티티가 아니라 값 타입을 컬렉션에 넣고 쓰는 것.
엔티티는 테이블 연관관계를 맺는데, 값 타입 리스트는 어떻게? DB는 값을 컬렉션으로 넣을 수 없거든..
=> 별도의 테이블로 뽑아야 한다.


값 타입 컬렉션 저장

값 타입 컬렉션은 CascadeType.ALL + orphanRemoval=true 설정을 포함.
값이니까 라이프사이클을 따를 수 밖에.

값 타입 컬렉션 조회
지연 로딩 전략 사용
값 타입 컬렉션 변경의 문제점
값 타입은 엔티티와 다르게 고유 식별자 개념이 없어서 값을 변경하면 추적이 어렵다.
값 타입 컬렉션에 요소를 추가하거나 변경 사항이 발생하면, 식별자가 없어서 주 엔티티와 연관된 모든 데이터를 메모리에 로딩하고, DB에서 모든 데이터를 삭제하고, 해당하는 값을 전부 다시 저장한다...

게다가 값 타입 컬렉션을 매핑하는 테이블은 모든 컬럼을 묶어서 기본 키를 구성해야 하므로 => null 입력X, 중복 저장X
값 타입 컬렉션 대안
실무에서는 상황에 따라 값 타입 컬렉션 대신에 일대다 관계를 위한 엔티티를 만들고, 여기에서 값 타입을 사용해라.
엔티티에 영속성 전이(Cascade) + 고아 객체 제거를 사용해서 값 타입 컬렉션 처럼 사용하면 된다.
(값 타입 컬렉션은 정말 단순하고 변경 추적이 필요없을 때만 사용해라)


참고: 임베티드 타입과 값 타입을 속성으로 사용하는 엔티티의 차이
@Embedded는 필드를 포함하는 엔티티와 동일한 테이블에 저장되는 반면,
엔티티(Entity)는 별도의 테이블로 관리되며, 더 복잡한 관계와 상태 관리를 위해 사용. @Entity로 정의된 클래스는 각각의 객체가 데이터베이스의 행을 나타낸다. 이는 독립된 테이블로 매핑되어 관리됨.
Element Collection 정리
1. 가능한 Entity를 만들어 일대다 관계로 사용하자. (+영속성 전이, 고아 객체 제거)
2. 단순하다면 사용해도 된다. 다만 기본키가 없어 변경 시 추적이 어렵고, 모든 값이 PK가 되어 생기는 문제를 알고 있자.
참고 자료 & 이미지 출처
자바 ORM 표준 JPA 프로그래밍 - 기본편 (김영한 님)
JPA 기반의 애플리케이션 설계 (조영호 님)
'JPA > JPA' 카테고리의 다른 글
| 객체지향 쿼리 언어(JPQL) - 중급 문법 (1) | 2024.09.16 |
|---|---|
| 객체지향 쿼리 언어(JPQL) - 기본 문법 (0) | 2024.09.15 |
| 프록시와 연관관계 관리 (3) | 2024.09.10 |
| 고급 매핑 (0) | 2024.09.10 |
| 다양한 연관 관계 매핑 (0) | 2024.09.09 |