[JPA] 연관관계 매핑 -2

2022. 12. 26. 16:30·Spring/JPA
728x90
반응형

연관관계 매핑시 고려해야할 사항

1. 다중성 (다대일, 일대다, 일대일, 다대다) - 이건 참고로 RDBMS 를 위함임 

2. 단방향 양방향

3. 연관주.

 

 

1) 다대일 다대다대

(외래키가 가는 곳이 다, 연관관계의 주인이 다, DB를 다스리는 쪽이 다, 조회만 하는쪽이 일) 

(지난 시간에 한 Member : Team 연관관계로 생각) 

(내가 DB에 넣을 칼럼과 동기화 시켜주면 됨. @JoinColumn(name = "team_id"))

 

2) 일대다 일대일대

(이건 연관주를 (일) 쪽에 두겠다는 것) 

(위에 모델을 뒤집은 것) 

(Team List<Members> 에서 DB를 다스림) 

(하지만 DB에서는 Member 쪽에 (다) 쪽에 외래키가 들어갈 수밖에 없음. 왜냐면 Team 쪽엔 그러면 ㅅㅂ member_id 계속 넣어줘야 하잖아. 한 칼럼이 ㅈㄴ 커짐) 

(정리 - 걍 쓰지 마 쫌) 

 

3) 일대일 

(이건 어떤 테이블에 외래키 넣든지 큰 관계는 없음 >> (로직상) 으로 외래키를 두는게 좋음) 

(외래 키에 DB 유니크 제약조건이 추가가 되는 것) 

 

Member (주 테이블) 와 Locker (대상 테이블) 

단방향 -> 연관주 설정한다

양방향 -> 만들고 싶으면 mappedBy 를 선언하고 반대객체를 그냥 또 넣어줌.

(다대일 연관관계와 큰 차이 없음) 

 

Locker 를 연관관계의 주인으로 잡으려면 테이블을 Locker 쪽에 걸면 됨. (반대로 이 상황에서 테이블을 Member쪽에 거는건 지원안함) 

 

>> 다대일이랑 걍 똑같다고 보면 됨. 

 

(참고로 DBA와 살짝 충돌이 있을 수도 있음) 

(로직 상은 NULLABLE 여부로 판단하는게 좋음)

> 멤버는 라커를 가지고 있어야 해? 꼭 그런건 아니야? 그러면 Member에 랔커가 있는게 더 좋음. 혹은 더 자주 Select 할 애.

> DB 쿼리 하나로 Locker 도 같이 가지고 있을 수 있기 때문. 하지만 락커에 있으면.... 굳이 멤버를 또 한번 select 해야함. 뭐 둘다 조회 칼럼으로 두면 문제가 아니긴 하다만. 

> 근데 DBA는 NULL 있는걸 싫어하기 때문에 Locker 쪽에 있는걸 좋아하기도 함. 

> 근데 대상테이블이 반대쪽에 있으면 양방향으로 해야함. 

 

나같은 경우 MemberInfo 와 1:1 관계이며, 1:1 관계에 있어서 Member가 당연히 연관관계의 주인. (MEMBER에서 Info 를 호출하는게 맞기 때문) 

 

그렇다면

Member

MemberInfo memberInfo

 

 

MemberInfo

Member member

 

??

 

=============================== 프록시 객체 관련해서 생각해볼 관점도 있음======================

 

 

4) 다대다 연관관계

> 다대다 (실무에서 쓰면 안됨~) 

> Linker 를 꼭 추가해서 일대다 관계들로 풀어내야 함. (FK 두개 가지는 객체) 

> 중요한 점 : DB상 안되므로 링커를 추가해서 연관관계를 풀어내야함. 링커를 추가했어도, 각 객체에서는 List<Product>, List<Member> 를 가지고 있는 것은 객체상 가능하기 떄문에, 그 기능을 JPA에서 지원하기도 한다. 

 

@ManyToMany
@JoinTable(name = "member_product_linker")
private List<PracticeProduct> products = new ArrayList<>();

 

이런식으로 추가해주면 Linker 를 거치지 않고도 조회가 가능하되, mplinker 테이블 역시 자동으로 생성된다. 

 

하지만... LINKER 하나를 통해서 둘 사이에 그 어떤 DATA들도 엄청 들어가게 된다. 따라서 위처럼 중간 테이블 없이 저렇게 사용하는건 말이 안됨. 꼭 Entity 하나를 더 선언하여서 충분한 데이터를 활용하고, 일대다 관계들을 두개로 풀어내야 한다. 

 

@Entity
public class MemberProductLinker {

    @Id
    @GeneratedValue
    private Long id;

    @ManyToOne
    @JoinColumn(name = "member_id")
    private PracticeMember member;

    @ManyToOne
    @JoinColumn(name = "product_id")
    private PracticeProduct product;

    private int count;
    private int isPassedDue;
    
}

 

이런식으로 관계를 풀어내서 관계에 대한 추가적인 데이터를 활용할 수 있어야 하고, 비즈니스상 반드시 그래야함. 또한, PK도 따로 가져가는걸 추천함. PK에 무슨 "의미"가 부여되지 않는게 좋음. 즉, PK 자체적으로 1개, FK 2개 다 따로따로가 좋음. 특정 FK를 자체 PK로 활용한다? 이건 문제가 될 수도 있음. 

 

 

==================================== 상속 관계 매핑===============================

DB에서도 상속관계가 정의될 수 있음. 객체 상 extends를 구현해주고 InheritanceType 을 지정해주면 됨

 

다음과 같은 상속 관계가 있다고 해보자.

 

@Entity
public class ExampleItem {
    @Id
    @GeneratedValue
    private Long id;
    private String name;
    private int price;
}

@Entity
public class ItemAlbum extends ExampleItem{
    private String artist;
}

@Entity
public class ItemBook extends ExampleItem {
    private String author;
    private String isbn;
}

@Entity
public class ItemMovie extends ExampleItem {
    private String director;
    private String actor;
}

 

 

가능한 테이블 전략 (@Inheritance., strategy =)

 

1) 조인 전략 (매우 정교) 

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class ExampleItem {
...
}

정말 상속관계 그래프처럼 매핑이 됨. 

(H2 DB 사진 보면 좋을듯) 

각각 부모 Item 은 id를 가져간채로, 칼럼들은 따로따로 들어가 있는다. (Member, MemberInfo 관계에 적용해도 좋을 듯) 

(뭐가 좋을지 생각을 한번 해봐도 좋을듯!) (DTYPE 주입 없이, 그냥 다 똑같이 부모 객체와 ID 공유한채로 들어감) 

(딱 MemberInfo 객체를 넣으면, Member 객체까지 다 Set 해서 넣을 수 있고, 그러면 칼럼별로 알아서 나뉘어진채로 들어가게 됨) 

@Test
@DisplayName("상속관계매핑 : InheritanceType.Joined")
void test1() {

    tx.begin();

    try {

        ItemMovie movie = new ItemMovie();
        movie.setDirector("aaa");
        movie.setActor("bbbb");
        movie.setName("바함사");
        movie.setPrice(1232);
        em.persist(movie); // 여기까지 해보고 실행시 확인이 위에 사진

        // 영컨 초기화
        em.flush();
        em.clear();

        ItemMovie itemMovie = em.find(ItemMovie.class, movie.getId());
        System.out.println("itemMovie = " + itemMovie);

        tx.commit();

    } catch (Exception e) {
        tx.rollback();
    } finally {
        em.close();
    }

    emf.close();
}

 

itemMovie를 조회하기 위해 ItemMovie 를 조회할 경우, movie.getId()를 하여도 Item을 거쳐서 가져오게 된다. 즉, item_id 로 인식을 하고 같은 id로 inner join 을 해서 가져오게 된다. 

 

Hibernate: 
    select
        itemmovie0_.id as id1_4_0_,
        itemmovie0_1_.name as name2_4_0_,
        itemmovie0_1_.price as price3_4_0_,
        itemmovie0_.actor as actor1_3_0_,
        itemmovie0_.director as director2_3_0_ 
    from
        item_movie itemmovie0_ 
    inner join
        items itemmovie0_1_ 
            on itemmovie0_.id=itemmovie0_1_.id 
    where
        itemmovie0_.id=?

 

* 참고)

정말 Inheritance Data Type 이 다양하다면, ITem 에 적재되는 칼럼들이 각각 어디에 속하는 칼럼들인지 구분해줄 필요 또한 있다. 따라서 Entity 에 다음과 같이 명시를 해준다면 이에 맞게 종류를 넣어주는 DTYPE 칼럼이 자동으로 들어가게 된다. 

 

상속받는 곳에서 @DiscriminatorValue 를 지정해주면 D-TYPE 에 들어가게 되는 값을 바꿔줄 수 있다. (DTYPE  은 엔간하면 있는게 좋음~ 쿼리 짜기도 좋음) 

 

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn
public class ExampleItem {
...
}

 

2) 단일 테이블 전략 (SINGLE_TABLE  / Default 로 지정된 전략) 

> 테이블 하나에 다 때려박고, DTYPE 으로 구분하는 것 (DTYPE 필수) 

 

[성능 테스트 같은 것들도 잘 해봐야 한다] 그 결과를 통해서 어떻게 하면 더 좋은 성능이 나올 수 있을지 잘 생각해야 함. 

 

 

3) 구현 클래스마다 테이블 전략

 

JOIN 전략이랑 비슷함. Item 을 없애버리고, Name, PRrice 로 선언된 칼럼들을 각각의 아이템들에게 때려 박아버림. 사실 객체상 연결되어 있다는 것만 빼면 그냥 다 따로따로 인거랑 큰 차이 없는 듯! 

 

이거 좋아보이긴 하는데 언제 망하냐면, 객체지향이니까 

em.find(Item.class, ~~.getId()) 했을 때, 찾을 때, ...... ㅋㅋㅋㅋㅋㅋㅋㅋ 다뒤짐. 

연관된 모든 테이블 다~~~ 뒤져서 찾음. 굉장히 비효율적으로 동작. 

 

>>>>>>>> 성능상 최악임. 절대 쓰지 말자~! 절대절대~

 

 

 

** 정리

Join 

장: 정규화 되어 있음, 실제 Model 과 가장 가까움. 외래키를 PK로 사용할 수 있음. 

단: 성능이 Single 보다 안나올 수도 있음. 

 

Single Table

장: 조회 성능이 빠름. SQL이 단순함 (join 필요 없음) 

단: 다 Null 을 허용해줘야 함. Album, Book 같은 값들을 nullable 이여야 movie 값이 들어갈 수 있음. 테이블이 지나치게 커질 수 있으므로, 조회 성능이 오히려 느려질 수도 있음. 

 

 

기본은 조인 전략을 가져가되

솔직히 확장될 일도 없어보이고, 좀 단순하고 명확한 쪽이다 싶으면 Single Table도 추천!

 

================================================

 

Mapped Super Class 

 

귀찮을 때 좋긴 좋은데, 나는 잘 모르겠음. 아닌가. 

 

공통 매핑 정보가 필요할 때 사용. (상속, 데이터 매핑과 별 상관 없음!) 

그냥 객체 입장에서 공통 매핑정보가 필요할 때 !!

 

>> 클래스 만들때마다 하기 좀 귀찮을 때. \

>> createdBy, createdDate, updatedBy, updatedDAte 이런거 활용할 때 좋긴 함. (이런 칼럼은 솔직히 무조건 있어야 함) 

>> 상속관계 아님!! 그리고 엔티티가 아니라 테이블화되지 않는다!!!  (매핑 정보만 엮어줌)

>> em.find(BaseEntity.class) 이런거 안됨. ID 도 없음.

>> 추상 클래스로 생성하는 것을 권장.  이것만 가지고 뭘 할 수 있는게 없기 때문 ( 누가 실수로 사용하는 것을 방지) 

 

실무에서 BaseEntity 만들면 편함. 

 

===================================================

728x90
반응형

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

[JPA] - 값 타입  (0) 2022.12.29
[JPA] 프록시와 연관관계 - 2  (0) 2022.12.28
[JPA] 프록시와 연관관계 정리  (0) 2022.12.26
[JPA] - 엔티티 매핑  (1) 2022.12.21
[JPA] JPA 개요와 영속성 컨텍스트  (0) 2022.12.18
'Spring/JPA' 카테고리의 다른 글
  • [JPA] 프록시와 연관관계 - 2
  • [JPA] 프록시와 연관관계 정리
  • [JPA] - 엔티티 매핑
  • [JPA] JPA 개요와 영속성 컨텍스트
문케이크
문케이크
    반응형
  • 문케이크
    누구나 개발할 수 있다
    문케이크
  • 전체
    오늘
    어제
    • 전체 보기 (122)
      • CS 이론 (13)
        • 운영체제 (8)
        • 네트워크 (2)
        • 알고리즘 (0)
        • Storage (3)
      • Spring (26)
        • Spring 기본 (12)
        • Spring 심화 (0)
        • JPA (11)
        • Spring Security (3)
      • 리액티브 (0)
        • RxJava (0)
      • SW 설계 (14)
        • OOP (0)
        • UML (3)
        • OOAD (0)
        • Design Pattern (11)
      • Java (8)
      • 웹 운영 (17)
        • AWS (15)
        • 운영 구축 (2)
      • Testing (3)
        • Unit (3)
      • Extra (3)
        • API 적용 (1)
      • 인프라 기술 (5)
        • Kubernetes (2)
        • Elasticsearch (3)
      • Logging (7)
        • Spring (5)
        • 인프라 (2)
      • 일상 (2)
        • 음식점 리뷰 (2)
        • Extra (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

    • 문케이크의 블로그
  • 인기 글

  • 태그

    BEAN
    Spring
    mockito
    단위테스트
    OOAD
    OOP
    SRP
    composition
    k8s
    n+1
    spring container
    Setter
    GoF
    di
    JPA
    디자인 패턴
    Composite
    lazy loading
    lombok
    elasticsearch
    객체지향
    analyzer
    junit
    spring boot
    Design Pattern
    runtime exception
    Configuration
    Java
    decorator
    김영한
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
문케이크
[JPA] 연관관계 매핑 -2
상단으로

티스토리툴바