Flamme Dev
  • IntroduceMyself
  • GOAL
    • 2021년 목표
    • 회고록
      • 2020년
  • COMMON
    • 자료구조
      • 시간복잡도
      • 스택/큐
    • 코드리뷰/스터디/세미나
      • Semina
        • Version control -1 (SVN/GIT)
        • Version control - 2 (GIT)
        • PostMan
        • JMeter
      • 스터디
        • 2021년
          • EffectiveKotlin
          • 이펙티브자바
        • 2020년
          • JPA Study
            • Chap1
            • Chap3
            • Chap4
            • Chap5
            • Chap6
            • Chap7
            • Chap8
            • Chap9
            • Chap10 -1
            • Chap10-2
            • Chap10-3
            • Chap12
            • Chap 13. 웹 애플리케이션과 영속성 관리
            • Chap14
      • 코드리뷰
        • Page 1
        • 개발 생각
        • APNs 라이브러리 교체
        • 파일 삭제 분투기
        • 신입 코드리뷰
          • 2020-09-02
          • 2020-09-03
          • 2020-09-10
        • Repository
          • Repositroy(20201124)
          • Repositroy(20201123)
          • Repositroy(20201120)
          • Repositroy(20201119)
          • Repositroy(20201117)
    • 개발 서적 / 동영상 강의
      • 동영상 강의
        • 진행 중
        • 완주한 것
      • 개발 서적
        • 읽은 것
          • 손에 잡히는 10분 SQL
            • 인덱스
            • 정리 본
        • 진행 중
          • 폴리글랏 프로그래밍
          • DDD-START
            • Chapter5 리포지터리의 조회 기능
            • Chapter4 리포지터리와 모델 구현
            • Chapter3 애그리거트
            • Chapter2 아키텍쳐 개요
            • Chapter1 도메인 모델의 시작
  • INFO
    • 유스콘 준비
    • intellij
      • Command line is too long.
    • 프로그래밍의 종류
      • Async Await
      • Reactive Programming
      • Imperative Programming
      • Functional Programming
        • Naver D2 함수형 프로그래밍 강의
      • Object Oriented Programing
        • 객체지향에 대해서 알아보는 영상
      • ProcedureOriented Programming
      • RX(ReactiveX)
      • OOP VS FP
      • Declarative Programming
    • Language
      • Kotlin
        • 박재성님 강의
        • Kotlin Spring CGLIB Error
        • Kotlin의 사용
        • coroutine
        • Kotlin JVM
      • JavaScript
      • JAVA
        • DefaultNonnull
        • effective78
        • Exception
        • JsonUnWrappers
        • 명명짓기
        • @JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
        • Enc Key
        • ServiceLoader
        • Annotation
        • JVM(Java Virtual Machine)
        • Java8
          • Functional 사용
          • Optional
          • Invalid Key size
        • Java13
          • Text Block
        • Basic
          • Generic
          • JVM
          • Interface, Implements
    • Framework
      • NodeJs
      • Xamarin
      • Vert.x
        • vert.x in action
        • eventbus
      • blockedthreadchecker
      • Why.. not root run..
      • Spring
        • Spring Test
        • Kotlin
        • ControllerAdvice 정리
        • JsonAnnotation
        • Spring Data R2DBC
        • SpringWebFlux
          • login
          • SpringWebFlux란?
        • JPA
          • QueryDSL 객체 주소값 확인할 것
          • SpringData-JPA에서 Save, SaveAll
          • @CompositeKey에 ManyToOne JoinColumn이 있을 경우
          • QueryDSL N+1 문제(@OneToOne)
          • QueryDSL설정
          • CreationTimestamp
          • Enum(@enumerated vs @convert)
        • SpringSecurity
          • aopAlliance
          • csrf 방어
          • antMatcher vs mvcMatcher
          • SpringSecurity를 왜 써야할까?
          • CoreSpringSecurity
            • AuthenticationProvider
            • AuthenticationManager
            • Authentication Flow
            • SecurityContextPersistenceFilter
            • SecurityContextHolder, SecurityContext
            • Authentication
            • 필터 초기화와 다중 보안 설정
            • DelegatingProxyChain, FilterChainProxy
            • 사이트 간 요청 위조 - CSRF, CsrfFilter
            • 예외 처리 및 요청 캐시 필터 : ExceptionTranslationFilter, RequestCacheAwareFilter
            • 인가 API - 권한 설정 및 표현식
            • SessionManagementFilter, ConcurrentSessionFilter
            • 동시 세션 제어 / 세션고정보호/ 세션 정책
            • AnonymousAuthenticationFilter
            • RememberMeAutheticationFilter
            • Logout,LogoutFilter
            • UsernamePasswordAuthenticationFilter
            • Form인증
            • 인증 API - 사용자 정의 보안 기능 구현
            • 인증 API - 스프링 시큐리티 의존성 추가
        • SpringMVC
          • Spring Bean Q&A
          • HttpServletRequest
          • @ControllerAdvice
          • Service와 ServiceImpl은 꼭 있어야할까?
          • SpringMVC-1
          • SpringMVC - validator와 Errors
          • SpringMVC - DispatcherServlet의 URL
          • Spring MVC - 기본설정(2) 및 HandlerInterceptor
          • SpringMVC-3
          • Spring MVC - ViewResolver
          • Spring MVC - XML/JSON
          • Spring MVC - Field Injection & Constructor Injection
        • SpringEtc
          • Transactional
          • @Atowired NullPointer
          • CircleReference
          • Mybatis
            • IBatis - sql에 Map
            • 1:1 Mapping시 Null
            • auto_Increment, selectKey
          • @Transactional
          • JacksonAnnotation
        • SpringAOP
        • SpringDI
    • Server
      • PM2
      • Tomcat
        • jks
        • Virtual Host(Port)
    • OS
      • Window
        • Active directory
      • IOS
      • Linux
        • samba/keroberos
        • Linux
          • unlimit / socket backLog
          • nohup
          • ; , & , &&, {}
          • 쉘
          • rc.local
          • ps aux | grep 프로세스이름
          • Vim
          • Su, Sudo
          • File Directory
        • IdConfig
        • 유용한 커맨드
        • 리눅스 대소문자
        • 소프트링크와 하드링크의 차이
        • ln -Tfs
        • //와 / 의 차이
        • Linux(202003)
          • rm
          • diff
          • cp
          • mv
          • tar 압축 시 어떻게 심볼릭 링크도 같이 압축할까?
          • tar 명령어
          • ln -s 심볼릭 링크
    • Network
      • API Architectural Styles
      • 포트 확인
      • HeartBeat Protocol
      • SSO(Single Sign On)
      • Cookie and Session
      • Tcp HandShake
      • WireShark
        • WireShark 옵션
        • WireShark 패킷분석
    • DataBase
      • DB락에 대해서 알아보기
      • Redis
      • MYSQL
        • Mysql TimeOut 설정
        • MysqlLog
        • SlowQuery Analyzing
        • PushNotification Stress Test
      • MSSQL
      • 데이터베이스 식별자 선택 전략
    • ETC
      • 이름 짓기
      • FFProbe
      • Talk
      • Untitled
Powered by GitBook
On this page
  • JPA-Cha9 값 타입
  • 기본값 타입
  • 임베디드 타입(복합 값 타입)
  • @AttributeOverride : 속성 재정의
  • 임베디드 타입과 null
  • 값 타입과 불변 객체
  • 값 타입 컬렉션
  • 값 타입 컬렉션의 제약사항
  • 정리

Was this helpful?

  1. COMMON
  2. 코드리뷰/스터디/세미나
  3. 스터디
  4. 2020년
  5. JPA Study

Chap9

이 글은 김영한님의 jpa책을 보고 공부한 흔적입니다.

JPA-Cha9 값 타입

JPA의 데이터 타입을 가장 크게 분류하면 엔티티 타입과 값 타입으로 나눌 수 있다.

값 타입은 다음 3가지로 나눌 수 있다.

  • 기본값 타입

    • 자바 기본 타입(int, double)

    • 래퍼 클래스 (Integer)

    • String

  • 임베디드 타입(embedded type)

  • 컬렉션 값 타입(collection value type)

기본값 타입

@Entity
@Data
public class Member {
    @Id @GeneratedValue
    private Long id;
    private String name;
    private int age;
}

Member에서의 String, int는 값 타입이다.

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

임베디드 타입이란?

JPA에서는 새로운 값 타입을 직접 정의해서 사용하는 것.

@Embaddable과 @Embedded가 있다. 둘다 기본 생성자가 필수이다.

  • @Embeddable : 값 타입을 정의하는 곳에 표시

  • @Embedded : 값 타입을 사용하는 곳에 표시

@Entity
public class Member {
    @Id @GeneratedValue
    private Long id;
    private String name;

    @Temporal(TemporalType.DATE) java.util.Date startDate;
    @Temporal(TemporalType.DATE) java.util.Date endDate;

    private String city;
    private String street;
    private String zipcode;


}
@Entity
public class Member { 

    @Id @GenratedValue
    private Long id;
    private String name;

    @Embedded Period workPerod;
    @Embedded Address homeAddress;


}


@Embeddable
public class Period { 

    @Temporal(TemporalType.DATE) java.util.Date startDate;
    @Temporal(TemporalType.DATE) java.util.Date endDate;

}

@Embeddable
public class Address { 

    @Column(name="city")
    private String city;
    private String street;
    private String zipcode;
}

임베디드 타입은 엔티티의 값일 뿐이다. 값이 속한 엔티티의 테이블에 매핑한다.

임베디드 타입을 사용하기 전과 후에 매핑하는 테이블이 같다.

즉, 임베디드 타입 덕분에 객체와 테이블을 아주 세밀하게 매핑하는 것이 가능하다.

결론적으로 잘 설계한 ORM 애플리케이션은 매핑한 테이블의 수보다 클래스의 수가 더 많다.

@Entity
public class Member {

    @Embedded Address address;
    @Embedded PhoneNumber phoneNumber;

}

@Embeddable
public class Address { 

    private String city;
    private String street;
    private String zipcode;
    @Embedded Zipcode zipcode;

}

@Embbedable
public class Zipcode { 

    String zip;
    String plusFour;

}

@Embbedable
public class PhoneNumber { 

    String areaCode;
    String localNumber;
    @ManyToOne PhoneServiceProvider provider

}

@Entity
public class PhoneServiceProvider {

    @Id String name;
}

@AttributeOverride : 속성 재정의

@Entity
public class Member { 

    @Id @GeneratedValue
    private Long id;
    private String name;

    @Embedded Address homeAddress;
    @Embedded Address companyAddress;

}
@Entity
public class Member { 

    @Id @GeneratedValue
    private Long id;
    private String name;

    @Embedded Address homeAddress;


    @Embedded 
    @AttributeOverrides({
        @AttributeOverride(name="city", column=@Column(name = "COMPANY_CITY")),
        @AttributeOverride(name="street", column=@Column(name = "COMPANY_STREET")),
        @AttributeOverride(name="zipcode", column=@Column(name = "COMPANY_ZIPCODE"))
})
    Address companyAddress;

}

임베디드 타입에 정희한 매핑정보를 재정의할 때 @AttributeOverride를 쓴다.

하지만 너무 많이 사용하면 엔티티코드가 지저분해진다는 단점이 있다.

임베디드 타입과 null

임베디드 타입이 null이면 메ㅐ핑한 컬럼 값은 모두 null이 된다.

    member.setAddress(null);
    em.persist(member);

회원 테이블의 주소와 관련된 CITY, STREET, ZIPCODE 컬럼 값이 모두 null이 된다.

값 타입과 불변 객체

값 타입의 공유 참조

임베디드 타입 같은 값 타입을 여러 엔티티에서 공유하면 위험하다.

    member1.setHomeAddress(new Address("oldCity"));
    Address address = member1.getHomeAddress();

    address.setCity("NewCity");
    member2.setHomeAddress(address);

member1과 member2의 도시는 모두 NewCity로 들어간다.

이것은 바로 공유 참조에 의해 일어난 것이다.

자바의 기본타입은 값을 대입하는 것만으로도 값이 복사되지만, 임베디트 타입처럼 직접 정의한 값 타입은 객체 타입이다.

객체 타입은 값을 대입하면 항상 참조 값을 전달하기 때문에 address.setCity("NewCity") 처럼 회원1의 address 값을 공유해서 사용 했을때 결과로 둘다 City가 NewCity로 되는것을 볼 수 있다.

어떻게 해결해야할까?

책에서는 두가지 방법을 추천한다.

  1. Clone을 만드는 방법

  2. setter메소드를 모두 제거해서 객체의 값을 수정하지 못하게 만드는 방법, 즉 불변 객체를 만드는 방법이다.

Clone을 만드는 방법

@Embeddable
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class AddressClone implements Cloneable{
    @Column
    private String city;
    private String street;
    private String zipcode;

    @Override
    public Object clone() throws CloneNotSupportedException {
        AddressClone clone = (AddressClone) super.clone();
        return clone;
    }

    public AddressClone(String city) {
        this.city = city;
    }

}

 public static void exClone(EntityManager em) throws CloneNotSupportedException {
        MemberEmbeddClone member = new MemberEmbeddClone();
        MemberEmbeddClone member1 = new MemberEmbeddClone();
        member.setUsername("형준");
        member1.setUsername("먕준");

        AddressClone a = new AddressClone("old");
        AddressClone b = (AddressClone) a.clone();
        b.setCity("new");

        member.setHomeAddress(a);
        member1.setHomeAddress(b);



        em.persist(member);
        em.persist(member1);

        em.flush();
    }

불변 객체

불변 객체란? 한번 만들면 절대 변경할 수 없는 객체.

왜 만들까? 객체를 불변하게 만들면 값을 수정할 수 없으므로 부작용을 원천 차단할 수 있기 떄문이다.

어떻게 만들까?

@Embeddable
public class Address { 

    private String city;

    protected Address() {}

    public Address(String city){this.city=city}

    public String getCity() {
        return city;
    }

    //setter는 만들지 않는다.

}

간단한 방법으로 생성자로만 값을 설정하고 수정자를 만들지 않으면 된다.

값 타입의 비교

  • 동일성(Identity) 비교 : 인스턴스의 참조 값을 비교, == 사용

  • 동등성(Equivalence) 비교 : 인스턴스의 값을 비교, equals()사용

값 타입 컬렉션

@ElementCollection, @CollectionTable을 쓰면 된다.

@Entity
public class Member { 

    @Id @GenratedValue
    private Long id;

    @Embedded Address homeAddress;

    @ElementCollection
    @CollectionTalbe(name = "FAVORITE_FOODS", 
      joinColumns = @JoinColumn(name = "MEMBER_ID"))
    @Column(name ="FOOD_NAME")
    private Set<String> favoriteFoods = new HashSet<String>;

    @ElementCollection
    @CollectionTalbe(name = "ADDRESS", 
       joinColumns = @JoinColumn(name = "MEMBER_ID"))
    private List<Address> addressHistory = new ArrayList<Address>();


}


@Embeddable
public class Address { 

    @Column
    private String city;
    private String street;
    private String zipcode;
}
Member member = new Member();

member.setHomeAddress(new Address("통영", "몽돌해수욕장", "660-123"));

member.getFavoriteFoods().add("짬뽕");
member.getFavoriteFoods().add("짜장");
member.getFavoriteFoods().add("탕수육");

member.getAddressHistory().add(new Address("서울", "강남", "660-123"));
member.getAddressHistory().add(new Address("서울", "강북", "660-123"));

em.persist(member);
Member member = em.find(Member.class, 1L);

Address homeAddress = member.getHomeAddress();

Set<String> favoriteFoods = member.getFavoriteFppds();

for (String favoriteFood : favoriteFoods) {
    System.out.println("favoriteFood = " + favoriteFood );
}

List<Address> addressHistory = member.getAddressHistory();

addressHistory.get(0);
    Member member = em.find(Member.class, 1L);

    member.setHomeAddress(new Address("새로운도시","신도시", "123456"));

    Set<String> favoritFoods = member.getFavoritFoods();
    favoriteFoods.remove("탕수육");
    favoriteFoods.add("치킨");

    List<Address> addressHistory = member.getAddressHistory();
    addressHistory.remove(new Address("서울","기존주소", "123456"));
    addressHistory.setHomeAddress(new Address("새로운도시","신도시", "123456"));

값 타입 컬렉션의 제약사항

엔티티는 식별자가 있으므로 엔티티의 값을 변경해도 식별자로 데이터베이스에 저장된 원본 데이터를 쉽게 찾아서 변경할 수있다.

반면에 값 타입은 식별자라는 개념이 없고 단순한 값들의 모음이므로 값을 변경해버리면 데이터베이스에 저장된 원본 데이터를 찾기 어렵다.

값이 변경되면 컬렉션이 남아있는 상황이 많은데 이것을 해결하기 위해서는

값 타입 컬렉션이 매핑된 테이블에 데이터가 많다면 값 타입 컬렉션 대신에 일대다 관계를 고려하기도 한다.

일대다 매핑에 영속성 전이(Cascade) + 고아 객체 제거(ORPHAN REMOVE) 기능을 적용하여 쓸 수도 있다.

값 타입 컬렉션을 사용할 때에 기본 키는 모두 생성키(PK)로 들어가야 한다. (?)

정리

엔티티 타입과 값 타입의 특징은 다음과 같다.

엔티티 타입의 특징

  • 식별자가 있다.

    • 엔티티 타입은 식별자가 있고 식별자로 구별할 수 있다.

  • 생명 주기가 있다.

    • 생성하고, 영속화하고, 소멸하는 생명 주기가 있다.

    • em.persist(entity)로 영속화 한다.

    • em.remove(entity)로 제거한다.

  • 공유할 수 있다.

    • 참조 값을 공유할 수 있따. 이것을 공유 참조라 한다.

    • 예를 들어 회원 엔티티가 있다면 다른 엔티티에서 얼마든지 회원 엔티티를 참조 할 수 있다.

값 타입의 특징

  • 식별자가 없다.

  • 생명 주익를 엔티티에 의존한다.

    • 스스로 생명주기를 가지지 않고 엔티티에 의존한다. 의존하는 엔티티를 제거하면 같이 제거된다.

  • 공유하지 않는 것이 안전하다.

    • 엔티티 타입과는 다르게 공유하지 않는 것이 안전하다. 대신에 값을 복사해서 사용해야 한다.

    • 오직 하나의 주인만이 관리해야 한다.

    • 불변 객체로 만드는 것이 안전하다.

PreviousChap8NextChap10 -1

Last updated 5 years ago

Was this helpful?