반응형
본 내용은 온라인 강의 사이트 인프런의 김영한 님의 강의 내용이 포함되어 있습니다.
'자바 ORM 표준 JPA 프로그래밍 - 기본편'
Intro
JPA의 데이터 타입을 분류하면 엔티티 타입과 값 타입으로 구분할 수 있다.
엔티티 타입
- @Entity로 정의하는 객체
- 데이터가 변해도 식별자를 통해 지속해서 추적할 수 있다.
- 예) 회원 엔티티의 키나 나이 등의 값을 변경해도 식별자로 인식 가능
값 타입
- int, Integer, String처럼 단순히 값으로 사용하는 자바 기본 타입이나 객체
- 식별자가 없고 숫자나 문자 같은 속성만 있어 변경 시 추적이 불가능하다.
- 예) 숫자 100을 200으로 변경하면 완전히 다른 값으로 대체
값 타입은 다음 3가지로 나눌 수 있다.
- 기본값 타입 : 자바 기본 타입, 래퍼 클래스, String
- 자바에서 제공하는 기본 데이터 타입
- 임베디드 타입(Embedded type, 복합 값 타입) : 좌표, 포지션 등
- JPA에서 사용자가 직접 정의한 값 타입
- 컬렉션 값 타입(Collection value type) : 기본값 타입이나 임베디드 타입을 저장할 수 있는 것
- 하나 이상의 값 타입을 저장할 때 사용
값 타입과 불변 객체
값 타입은 복잡한 객체를 조금이라도 단순화하려고 만든 개념이다.
따라서, 값 타입은 단순하고 안전하게 다룰 수 있어야 한다.
값 타입 공유 참조
- 임베디드 타입 같은 값 타입을 여러 엔티티에서 공유하면 위험하다.
- 예상치 못한 곳에서 문제가 발생하는 부작용(side effect) 발생
Member member1 = new Member();
member1.setName("member1");
member1.setHomeAddress(address);
em.persist(member1);
Member member2 = new Member();
member2.setName("member2");
member2.setHomeAddress(address);
em.persist(member2);
// member2의 City를 newCity로
member2.getHomeAddress().setCity("newCity");
이 경우 member2의 주소를 “NewCity”로 변경하길 원했지만, member1의 주소도 같이 변경된다.
- 영속성 컨텍스트에서는 회원1과 회원2 둘 다 city 속성이 변경된 것으로 판단하여 각각 UPDATE SQL을 실행
이처럼 공유 참조로 인해 발생하는 문제는 찾아내기가 어렵다. 이 경우 값을 복사해서 사용해야 한다.
값 타입 복사
값 타입의 실제 인스턴스 값을 공유하는 것은 예상치 못한 곳에서 문제가 발생할 수 있다.
따라서, 값(인스턴스)을 복사해서 사용해야 한다.
Address address = new Address("city", "street", "10000");
Member member1 = new Member();
member1.setName("member1");
member1.setHomeAddress(address);
em.persist(member1);
Address copyAddress = new Address(address.getCity(), address.getStreet(), address.getZipcode());
Member member2 = new Member();
member2.setName("member2");
member2.setHomeAddress(copyAddress);
em.persist(member2);
// member2의 City를 newCity로
member2.getHomeAddress().setCity("newCity");
- 공유 참조를 하지 않기 위해 해당 참조 객체를 복사해서 사용한다.
- 공유 참조로 인해 발생하는 부작용을 피할 수 있다.
객체 타입의 한계
임베디드 타입처럼 직접 정의한 값 타입은 자바의 기본 타입이 아닌 객체 타입이다.
- 기본 타입은 값을 대입하면 해당 값을 복사한다.
- 하지만, 객체 타입은 참조 값을 직접 대입하는 것을 막을 방법이 없다.
- 객체의 공유 참조는 피할 수 없는 한계가 있다.
// 기본 타입
int a = 10;
int b = a; // 기본 타입은 값을 복사
b = 4; // a = 10, b = 4
// 객체 타입
Address a = new Address("Old");
Address b = a; // 객체 타입은 참조를 전달
b.setCity("New"); // a와 b 모두 New로 변경
불변 객체
불변 객체는 생성 시점 이후 절대 값을 변경할 수 없는 객체를 의미한다.
값 타입은 부작용 걱정 없이 사용할 수 있어야 한다. 따라서 객체를 불변하게 만들어 애초에 수정할 수 없도록 할 필요가 있다.
- 값 타입은 불변 객체(immutable object)로 설계해야 한다.
- 생성자로만 값을 수정하고 수정자(Setter)를 만들지 않으면 된다.
즉, 값 타입을 생성자로만 값을 설정하고, Setter를 선언하지 않는 것으로 불변 객체로 만들 수 있다.
- 부작용 문제 해결
불변 객체의 값 수정
불변 객체의 값을 수정해야 할 경우에는 새로운 객체를 생성하여 필요한 부분만 수정해야 한다.
Address address = new Address("city", "street", "10000");
Member member1 = new Member();
member1.setName("member1");
member1.setHomeAddress(address);
em.persist(member1);
// 수정
Address newAddress = new Address("NewCity", address.getStreet(), address.getZipcode());
member1.setHomeAddress(newAddress);
- 불변이라는 작은 제약으로 부작용이라는 큰 재앙을 막을 수 있다.
반응형
'프레임워크(Framework) > JPA' 카테고리의 다른 글
[JPA] 값 타입 컬렉션 - 값 타입 (4) (0) | 2022.12.11 |
---|---|
[JPA] 값 타입의 비교 - 값 타입 (3) (0) | 2022.12.10 |
[JPA] 기본값 타입과 임베디드 타입 - 값 타입 (1) (0) | 2022.12.08 |
[JPA] 영속성 전이(CASCADE)와 고아 객체 (0) | 2022.12.07 |
[JPA] 프록시와 연관관계 관리(지연 로딩과 즉시 로딩) (0) | 2022.12.06 |