JPA - 값 타입

2024. 1. 20. 15:45spring/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