반응형
JPA 게시글은 대부분 인프런의 김영한님의 강의인 '자바 ORM 표준 JPA 프로그래밍' 기반으로 내용을 정리했습니다.
값 타입과 불변 객체
값 타입 공유 참조
- 임베디드 타입 같은 값 타입을 여러 엔티티에서 공유하면 위험하다.
- 부작용(side effect) 발생
위의 그림처럼 city 값을 NewCity로 변경하면 회원1과 2가 들고 있던 city도 NewCity로 변경된다.
Address address = new Address("city", "street", "100");
Member member1 = new Member();
member1.setUsername("member1");
member1.setHomeAddress(address); // 같은 address 공유
em.persist(member1);
Member member2 = new Member();
member2.setUsername("member2");
member2.setHomeAddress(address); // 같은 address 공유
em.persist(member2);
member1.getHomeAddress().setCity("newCity"); // address 변경
member1과 member2에 같은 address를 넣고 저장한 후에 member1의 address를 변경하고 DB를 확인해보자.
원래는 member1의 주소만 변경하려 했는데 의도치 않게 member2의 주소도 새로운 주소로 변경되었다. 이러한 사이드 이펙트는 잡기 힘드니 애초에 조심해야 한다.
만약에 member1과 member2의 주소가 '동일'하게 변경되길 원해서 이렇게 작성한 경우 address를 임베디드 타입이 아닌, 객체로 만들어서 공유해야 함이 맞다.
값 타입 복사
- 값 타입의 실제 인스턴스인 값을 공유하는 것은 위험하다.
- 대신 값(인스턴스)을 복사해서 사용해야 한다.
Address address = new Address("city", "street", "100");
Member member1 = new Member();
member1.setUsername("member1");
member1.setHomeAddress(address);
em.persist(member1);
Address copyAddress = new Address(address.getCity(), address.getStreet(), address.getZipcode());
Member member2 = new Member();
member2.setUsername("member2");
member2.setHomeAddress(copyAddress);
em.persist(member2);
member1.getHomeAddress().setCity("newCity");
기존의 Address의 값을 copyAddress 객체를 하나 생성해서 그대로 복사하여 copyAddress를 member2에 넣어준다. 이런 식으로 복사 후 값을 넣으면 원하던 의도대로 동작하는 걸 확인할 수 있다.
객체 타입의 한계
- 항상 값을 복사해서 사용하면 공유 참조로 인해 발생하는 부작용을 피할 수 있다.
- 문제는 임베디드 타입처럼 직접 정의한 값 타입은 자바의 기본 타입이 아니라 객체 타입이다.
- 자바 기본 타입에 값을 대입하면 값을 복사한다.
- 객체 타입은 참조 값을 직접 대입하는 것을 막을 방법이 없다.
- 객체의 공유 참조는 피할 수 없다.
불변 객체
- 불변 객체 : 생성 시점 이후 절대 값을 변경할 수 없는 객체
- 객체 타입을 수정할 수 없게 만들면 부작용을 차단할 수 있음
- 값 타입은 불변 객체(immutable object)로 설계해야 함
- 생성자로만 값을 설정하고 수정자(Setter)를 만들지 않으면 된다.
- 참고 : Integer, String은 자바가 제공하는 대표적인 불변 객체이다.
Address에 있는 setter를 지우거나 혹은 setter의 접근 제한자를 모두 private로 만들어버리면 불변 객체로 만들 수 있다. 예제에서 setter를 모두 지우면 getter에 뭔가 오류가 나서 접근 제한자를 변경했다.
그럼 이 상태에서 member1의 address 값을 변경하려면 어떻게 해야 할까?
Address address = new Address("city", "street", "100");
Member member1 = new Member();
member1.setUsername("member1");
member1.setHomeAddress(address);
em.persist(member1);
Address newAddress = new Address("NewCity", address.getStreet(), address.getZipcode());
member1.setHomeAddress(newAddress);
그냥 새로운 address를 만들고 그 address를 member1에 set 해주면 된다.
반응형