김영한 님의 '자바 ORM 표준 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 : 값 타입을 사용하는 곳에 표시한 엔티티에서 같은 값 타입을 사용하면 컬럼명이 중복되는데 이때 @AttributeOverrides, @AttributeOverride를 사용해서 컬럼 명 속성을 재정의 해줄 수 있다.
임베디드 타입의 값이 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 애노테이션을 사용하면 된다.
값 타입 컬렉션은 지연 로딩 전략을 사용한다는 점을 명심하자 !
값 타입은 정말 값 타입이라 판단될 때만 사용해야 한다. 식별자가 필요하고 지속해서 값을 추적, 변경해야 한다면 그것은 값 타입이 아닌 엔티티이다.