JPA 값 타입 - 값 타입과 불변 객체

2022. 7. 12. 23:06·공부/JPA
반응형

출처 : 자바 ORM 표준 JPA 프로그래밍 인프런 강의

 

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에 넣어준다. 이런 식으로 복사 후 값을 넣으면 원하던 의도대로 동작하는 걸 확인할 수 있다.

member2는 그대로 city이다.

 

객체 타입의 한계

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

 

불변 객체

  • 불변 객체 : 생성 시점 이후 절대 값을 변경할 수 없는 객체
  • 객체 타입을 수정할 수 없게 만들면 부작용을 차단할 수 있음
  • 값 타입은 불변 객체(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 해주면 된다.

 

반응형
저작자표시 비영리 변경금지 (새창열림)
'공부/JPA' 카테고리의 다른 글
  • JPA 값 타입 - 값 타입 컬렉션
  • JPA 값 타입 - 값 타입의 비교
  • JPA 값 타입 - 임베디드 타입
  • JPA 값 타입 - 기본값 타입
데부한
데부한
어차피 할 거면 긍정적으로 하고 싶은 개발자
    반응형
  • 데부한
    동동이개발바닥
    데부한
  • 전체
    오늘
    어제
    • 분류 전체보기 (307)
      • 방통대 컴퓨터과학과 (27)
        • 잡담 (9)
        • 3학년1학기 (17)
      • 프로젝트 및 컨퍼런스 회고 (1)
        • 프로젝트 (4)
        • 한이음 프로젝트 (0)
        • 회고 (3)
      • 공부 (165)
        • Spring (37)
        • JPA (71)
        • 인프런 워밍업 클럽_BE (10)
        • Java (6)
        • React.js (27)
        • 넥사크로 (11)
        • 기타 (3)
      • 알고리즘 (85)
        • 알고리즘 유형 (10)
        • 알고리즘 풀이 (57)
        • SQL 풀이 (18)
      • 에러 해결 (13)
      • 잡담 (7)
        • 국비교육 (2)
        • 구매후기 (5)
        • 진짜 잡담 (0)
  • 블로그 메뉴

    • Github
    • Linkedin
    • 홈
    • 방명록
    • 글쓰기
    • 관리
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    코딩테스트
    react
    스프링부트
    SQL
    토비의스프링부트
    egov
    전자정부프레임워크
    springboot
    자바스크립트
    개발자
    기출문제
    프로그래머스
    Java
    JPA
    Spring
    알고리즘
    백준
    토이프로젝트
    MSA
    넥사크로
    인프런
    SpringBoot를 이용한 RESTful Web Service 개발
    프론트엔드
    IT
    oracle
    에러해결
    RESTful
    운영체제
    QueryDSL
    방통대
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
데부한
JPA 값 타입 - 값 타입과 불변 객체
상단으로

티스토리툴바