값 타입

유동우·2023년 8월 7일
0
post-thumbnail

기본 값 타입

JPA의 데이터 타입 분류

  • 엔티티 타입
    • @Entity로 정의된 객체
    • 데이터가 변해도 식별자로 지속해서 추적이 가능하다 (중요)
    • ex) 회원 엔티티의 키나 나이값이 변경되어도 식별자로 인식이 가능하다
  • 값 타입
    • int, Integer, String 처럼 단순 값으로 사용하는 자바 기본 타입 or 객체
    • 식별자가 없고 값만 존재 -> 추적 불가능
  • 기본 값 타입
    • 생명주기를 엔티티에 의존한다 (회원 삭제시 그 필드인 이름, 나이도 삭제)
    • 값 타입은 공유하면 안된다 (회원 이름 변경시 다른 회원의 이름도 변경 되면 안됨)

cf) 자바의 기본 타입은 절대 공유X

기본 타입은 값을 복사한다
Integer 같은 래퍼 클래스나 String 같은 특수한 클래스는 공유가능 객체이지만 변경 할 수 없다
-> 이게 무슨 소리냐?

Integer a = new Integer(10);
Integer b = a;

a.setValue(20); // 존재 가정

//출력 시 a == b == 20 
//하지만 a 값을 바꿀 방법조차 없음 

임베디드 타입

임베디드 타입 이란?

  • 새로운 값 타입을 직접 정의할 수 있다
  • 기본 값 타입을 모아서 만들었기 때문에 복합 값 타입 이라고도 한다
  • int, String 과 같은 값 타입이다 -> 추적 불가
@Entity
public class Member{
      @Embedded //상위 계층에 표기
      private Address homeAddress;
      ...
}


@Embeddable //하위 계층에 표기
public class Address {
      private String city;
      private String street;
      private String zipcode;
      
	  public Address() { //디폴트 생성자 필수

      }
      ...

임베디드 타입은 엔티티의 값일 뿐이고, 사용 전 후에 매핑하는 테이블은 같다

그럼 왜 임베디드 타입을 사용할까?
-> 객체와 테이블을 아주 세밀하게 매핑하는 것이 가능하다
(ex) Address의 좌표값 등 재사용성을 높일 수 있다

위 그림처럼 임베디드 된 클래스에서 엔티티를 가질 수 있다.
(외래키만을 참조하면 되기 때문)


한 엔티티에서 같은 값을 사용하고 싶다..

@AttributeOverride(s) : 속성 재정의

public Member(){
    	@Embedded
        private Address homeAddress;
        
        @Embedded
        @AttributeOverrides({
                @AttributeOverride(name = "city",
                        column = @Column(name = "WORK_CITY")),
                @AttributeOverride(name = "street",
                        column = @Column(name = "WORK_STREET")),
                @AttributeOverride(name = "zipcode",
                        column = @Column(name = "EMP_END"))
        })
        private Address workAddress;
}

값 타입과 불변 객체

자바의 기본타입은 값을 복사하기 때문에 초기 설정값에는 지장이 없다

int a = 10;
int b = a; //값 복사
b = 4; 

자바의 객체 타입은 하나의 인스턴스에 대해 참조를 복사하여 넘기기 때문에 값이 모두 변경된다

Address a = new Address("old");
Address b = a; //참조
b.setCity("new);

참조를 막을 방법이 없기 때문에 불변 객체로 만들어야 한다

불변객체

  • 정의: 생성 시점 이후 절대 값을 변경할 수 없는 객체
  • 부작용을 차단하기 위함
  • 값 타입은 불변 객체로 설계해야한다
  • 생성자로만 값을 설정하고, 수정자(Setter)를 만들지 않으면 된다 (or Private)
  • ex) Integer, String 은 자바의 대표적인 불변 객체이다

그렇다면 Setter가 없는 상황에서 값을 수정하고 싶으면 어떻게 할까?
=> 객체를 새로 만들어서 수정하고 싶은 부분만 수정한 후 다시 통째로 넣어줘야한다.

Address newAddress = new Address("NewCity", 
						address.getStreet(), address.getZipcode());
member1.setHomeAddress(newAddress);

값 타입의 비교

값 타입들의 비교는 항상 equals를 사용하자

Address add2 = new Address("city", "street", "10000");
Address add1 = new Address("city", "street", "10000");

System.out.println("add1 == add2: " + (add1 == add2)); //false
System.out.println("add1 equals add2: " + (add1.equals(add2))); //false
//equals의 기본은 == 이기 때문에 false => equals 메서드 오버라이드 필요

(cf)
//String의 equals는 == 비교로 구현되어 있지 않음
//String.java
public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
}

값 타입 컬렉션

(값타입)컬렉션 또한 값타입이기 때문에 em.persist(member) 만으로 모든 값타입 컬렉션에 대한 insert 쿼리가 발생한다

Member member = new Member();

member.setUsername("member1");
member.setHomeAddress(new Address("homeCity", "street", "1000"));

member.getFavoFoods().add("치킨");
member.getFavoFoods().add("족발");

member.getAddHistory().add(new Address("old1", "street","10000"));
member.getAddHistory().add(new Address("old2", "street","10000"));

em.persist(member);

값 타입 컬렉션은 영속성 전이(cascade) + 고아 객체 제거 기능을 필수로 가진다고 생각하자

--- 중간 과정 생략 (쿼리 이해가 잘 안됨 추후에 다시 확인) ---

결론: 값타입 컬렉션은 쿼리가 발생하면 이전에 저장되어 있는 값을 모두 날리므로 사용하지 말고, 일대다 관계를 고려하자

  • 일대다 관계를 위한 엔티티를 생성하고, 여기에 값 타입을 사용
  • 영속성 전이(cascade), 고아 객체 제거를 사용해서 값 타입 컬렉션처럼 사용

그렇다면 값타입 컬렉션은 언제 사용할까?
=> 정말 단순한 경우, 추적할 필요가 없고 업데이트를 하지 않을 경우

실전 예제 6 - 값 타입 매핑

Reference
김영한 님 - 자바 ORM 표준 JPA 프로그래밍 - 기본편

profile
효율적이고 꾸준하게

1개의 댓글

comment-user-thumbnail
2023년 8월 7일

이렇게 유용한 정보를 공유해주셔서 감사합니다.

답글 달기