본문 바로가기
Study/JPA

값 타입 1

by _비니_ 2024. 7. 27.

📌 기본값 타입

 

엔티티 타입

  • @Entity로 정의하는 객체
  • 데이터가 변해도 식별자로 지속해서 추적 가능
  • 예) 회원 엔티티의 키나 나이 값을 변경해도 식별자로 인식 가능

값 타입

  • int, Integer, String처럼 단순히 값으로 사용하는 자바 기본 타입이나 객체
  • 식별자가 없고 값만 있으므로 변경시 추적 불가
  • 예) 숫자 100을 200으로 변경하면 완전히 다른 값으로 대체

값 타입 분류

<자바가 제공하는..?>

  • 기본값 타입
    • 자바 기본 타입(int, double)
    • 래퍼 클래스(Integer, Long)
    • String

<JPA에서 정의해서 사용?>

  • 임베디드 타입(embedded type, 복합 값 타입)
  • ex) x, y좌표를 묶어서 값으로 사용하고 싶을 때?
  • 컬렉션 값 타입(collection value type)

기본값 타입 (ex- String name, int age)

  • 생명주기를 엔티티의 의존
    • 예) 회원을 삭제하면 이름, 나이 필드도 함께 삭제
  • 값 타입은 공유하면 안됨
    • 예) 회원 이름 변경시 다른 회원의 이름도 함께 변경되면 안됨

🚨 참고 🚨

 

자바의 int, double과 같은 기본타입(primitive type)은 절대 공유되지 않음!!

⇒ 그래서 값 타입으로 사용했을 때 안전함

  • 기본 타입은 항상 값을 복사함
  • Integer같은 래퍼 클래스나 String 같은 특수한 클래스는 공유가능한 객체이지만 변경할 방법이 없음

 

📌 임베디드 타입(복합 값 타입)

 

 

임베디드 타입(복합 값 타입) / 내장타입

  • 새로운 값 타입을 직접 정의할 수 있음
  • JPA는 임베디드 타입(embedded type)이라 함
  • 주로 기본 값 타입을 모아서 만들어서 복합 값 타입이라고도 함
  • int, String과 같은 값 타입

회원 엔티티는 이름, 근무 시작일, 근무 종료일, 주소 도시, 주소 번지, 주소 우편번호를 가진다.

→ 회원 엔티티는 이름, 근무 기간, 집 주소를 가진다.

(이렇게 복잡하게 말하지 않고 이렇게 묶어냄. 이렇게 묶어낼 수 있는게 임베디드 타입!?)

클래스 2개를 새로 만듦

@Embeddable
public class Period {

    private LocalDateTime startDate;
    private LocalDateTime endDate;

//Getter,Setter...
@Embeddable
public class Address {
    private String city;
    private String street;
    private String zipcode;

//Getter,Setter...
@Entity
public class Member extends BaseEntity{
    @Id @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;
    @Column(name = "USERNAME")
    private String username;

    @Embedded
    private Period wordPeriod;

    @Embedded
    private Address homeAddress;
}

임베디드 타입과 테이블 매핑

  • 임베디드 타입은 엔티티의 값일 뿐이다.
  • 임베디드 타입을 사용하기 전과 후에 매핑하는 테이블은 같다.
  • 객체와 테이블을 아주 세밀하게(find-grained) 매핑하는 것이 가능
  • 잘 설계한 ORM 애플리케이션은 매핑한 테이블의 수보다 클래스의 수가 더 많음

임베디드 타입 연관관계

  • 임베디드 타입은 임베디드 타입을 가질 수 있음
  • 임베디드 타입은 엔티티를 가질 수 있음
    • 우리 코드 예시에서는 Address에 private Member member; 가 가능하다는 의미

@AttributeOverride: 속성 재정의

  • 한 엔티티에서 같은 값 타입을 사용하면? ⇒ 에러남
@Embedded
private Address homeAddress;

@Embedded
private Address workAddress;

 

@AttributeOverrides, @AttributeOverride를 사용해서 컬러 명 속성을 재정의

@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="WORK_ZIPCODE"))
})
private Address workAddress;

 

 

임베디드 타입의 값이 null이면 매핑한 컬럼 값은 모두 null

@Embedded
private Address homeAddress = null;

 

 

📌 값 타입과 불변객체

값 타입은 복잡한 객체 세상을 조금이라도 단순화하려고 만든 개념

따라서 값 타입은 단순하고 안전하게 다룰 수 있어야 한다.

값 타입 공유 참조

  • 임베디드 타입 같은 값 타입을 여러 엔티티에서 공유하면 위험함
  • 부작용(side effect) 발생

 

회원1과 회원2를 같은 city를 사용하고 있는데, 이를 NewCity를 변경 (하나만 변경할 의도로)

⇒ 둘 다 변경되는 부작용 발생 !!

>> 만약 둘 다 변경되길 원하면 값타입이 아닌 엔티티로 사용하는 것이 맞음

값 타입 복사

  • 값 타입의 실제 인스턴스인 값을 공유하는 것은 위험
  • 대신 값(인스턴스)를 복사해서 사용함!

객체 타입의 한계

  • 항상 값을 복사해서 사용하면 공유 참조로 인해 발생하는 부작용을 피할 수 있다.
  • 문제는 임베디드 타입처럼 직접 정의한 값 타입은 자바의 기본타입이 아니라 객체 타입이다.
  • 자바 기본 타입에 값을 대입하면 값을 복사한다.
  • 객체 타입은 참조 값을 직접 대입하는 것을 막을 방법이 없다.
  • 객체의 공유 참조는 피할 수 없다.

기본 타입에서는 b를 4로 변경해도 a의 값은 10으로 유지됨. 아무 문제 없음

(값을 복사)

하지만 객체 타임에서는 b.setCity를 New로 변경하면 둘 다 변함. a와 b는 같은 인스턴스를 가리키고 있음.

(참조를 복사해 전달)

불변 객체

  • 객체 타입을 수정할 수 없게 만들면 부작용을 원천 차단
  • 값 타입은 불변 객체(immutable object)로 설계해야함
  • 불변 객체: 생성 시점 이후 절대 값을 변경할 수 없는 객체
  • 생성자로만 값을 설정하고 수정자(Setter)를 만들지 않으면 됨
  • 참고: Integer, String은 자바가 제공하는 대표적인 불변 객체

불변이라는 작은 제약으로 부작용이라는 큰 재앙을 막을 수 있다.

 

 

📌 값 타입의 비교 (equals 써야 함.)

 

int a = 10; 
int b = 10;
System.out.println("a==b" + (a==b)); //true

Address address1 = new Address(“서울시”);
Address address2 = new Address(“서울시”);
System.out.println("address1==address2" + (address1==address2)); //false

동일성 비교와 동등성 비교를 구분하여 사용해야 함.

  • 동일성(identity) 비교: 인스턴스의 참조 값을 비교, == 사용
  • 동등성(equivalence) 비교: 인스턴스의 값을 비교, equals() 사용
  • 값 타입은 a.equals(b)를 사용해서 동등성 비교를 해야 함
  • 값 타입의 equals() 메소드를 적절하게 재정의(주로 모든 필드 사용)

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    Address address = (Address) o;
    return Objects.equals(city, address.city) && Objects.equals(street, address.street) && Objects.equals(zipcode, address.zipcode);
}

@Override
public int hashCode() {
    return Objects.hash(city, street, zipcode);
}

Object equals를 가지고 3가지를 &비교

 

반응형

'Study > JPA' 카테고리의 다른 글

프로젝션과 페이징  (0) 2024.07.27
객체지향 쿼리 언어 소개  (0) 2024.07.27
값 타입 2  (0) 2024.07.27
프록시 ) 영속성 전이(CASCADE)와 고아 객체  (0) 2024.07.26
프록시  (0) 2024.07.25