2024. 1. 20. 15:45ㆍspring/JPA
JPA 데이터 타입을 가장 크게 분류하면 엔티티 타입과 값 타입으로 나눌 수 있다. 엔티티 타입은 @Enity로 정의하는 객체이고 값 타입은 원시 타입이나 참조 타입 객체를 말한다.
값 타입은 3가지로 나눌 수 있다.
1. 기본값 타입
- 자바 기본 타입
- 래퍼 ㅡㄹ래스
- String
2. 임베디드 타입
3. 컬렉션 값 타입
기본값 타입
가장 단순한 기본값 타입
public class Member extends BaseEntity {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
@Column(name = "USERNAME")
private String username;
}
String, Long, int가 값 타입이다.
임베디드 타입
새로운 값 타입을 직접 정의해서 사용할 수 있다.
@Entity
public class Member extends BaseEntity {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
@Column(name = "USERNAME")
private String username;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "TEAM_ID")
private Team team;
@OneToMany(mappedBy = "member")
private List<MemberProduct> memberProducts = new ArrayList<>();
//기간
//private LocalDateTime startDate
//private LocalDateTime endDate
@Embedded
private Period workPeriod;
}
=======================================================================
@Embeddable
public class Period {
private LocalDateTime startDate;
private LocalDateTime endDate;
}
회원이 상세한 데이터를 그대로 가지고 있는 것은 객체지향적이지 않으며 응집력만 떨어뜨린다. 대신 근무 기간, 주소 같은 타입이 있다면 코드가 더 명확해질 것이다.
새로 정의한 값 타입들은 재사용할 수 있고 응집도도 아주 높다. 임베디드 타입을 사용하려면 다음 2가지 어노테이션이 필요하다. (둘 중 하나는 생략가능)
@Embeddable : 값 타입을 정의하는 곳에 표시
@Embedded : 값 타입을 사용하는 곳에 표시
값 타입과 불변 객체
임베디드 타입 같은 값 타입을 여러 엔티티에서 공유하면 위험하다.
Adress adress = new Adress("city", "street", "zipcode");
Member member = new Member();
member.setUsername("member1");
member.setAdress(adress);
em.persist(member);
Member member2 = new Member();
member2.setUsername("member2");
member2.setAdress(adress);
em.persist(member2);
member.getAdress.setCity("newCity");
member2 와 member1이 같은 주소 객체의 참조를 공유하고 있기 때문에 member1이 주소의 데이터 필드를 변경한다면 그 영향이 member2의 주소 객체에도 미친다.
해결책1 : 값 타입 복사
Adress adress = new Adress("city", "street", "zipcode");
Member member = new Member();
member.setUsername("member1");
member.setAdress(adress);
em.persist(member);
Adress copyAdress = new Adress("city", "street", "zipcode");
Member member2 = new Member();
member2.setUsername("member2");
member2.setAdress(copyAdress);
em.persist(member2);
member.getAdress.setCity("newCity");
하지만 크리티컬한 문제점이 있는데 복사하지 않고 원본의 참조 값을 직접 넘기는 것을 막을 방법이 없다. 객체의 공유 참조는 피할 수 없으니 객체의 값을 수정하지 못하게 만들면 된다.
해결책2 : 불변 객체
Adress adress = new Adress("city", "street", "zipcode");
Member member = new Member();
member.setUsername("member1");
member.setAdress(adress);
em.persist(member);
Member member2 = new Member();
member2.setUsername("member2");
member2.setAdress(adress);
em.persist(member2);
//Setter를 없애서 아예 변경을 못하게 만든다.
//member.getAdress.setCity("newCity");
객체를 불변하게 만들면 부작용 걱정 없이 사용할 수 있다. 무조건 값 타입은 불변 객체로 설계하자
'spring > JPA' 카테고리의 다른 글
JPQL(2) - 프로젝션 (0) | 2024.01.24 |
---|---|
JPQL(1) - 기본 문법 (0) | 2024.01.24 |
JPA - 즉시 로딩과 지연 로딩, 영속성 전이, 고아 객체 (0) | 2024.01.19 |
JPA - 프록시 (0) | 2024.01.19 |
고급매핑 - 상속 관계 매핑 (0) | 2024.01.15 |