가자공부하러!

Hibernate(5) - 연관관계 매핑 본문

공부/Java

Hibernate(5) - 연관관계 매핑

오피스엑소더스 2019. 11. 20. 16:23

1. 문제점

  > 객체를 테이블에 맞추어 데이터 중심으로 모델링하면, 협력 관계를 만들 수 없다.

    - 테이블은 외래 키로 조인을 사용해서 연관된 테이블을 찾는다.

    - 객체는 참조를 사용해서 연관된 객체를 찾는다.

 

2. 단방향 연관관계

  > 단방향 매핑으로 끝내는게 베스트

    - 단방향 매핑만으로도 이미 연관관계 매핑은 완료된 것이기 때문

  > 객체 지향 모델링

    - Member가 필드로 Team타입의 변수를 가짐

      - @ManyToOne, @JoinColumn(name = "TEAM_ID")

 

3. 양방향 연관관계

  > FK로 엮인 DB 테이블 끼리는 JOIN을 통해 서로의 데이터를 쉽게 조회할 수 있다.

  > Entity가 테이블처럼 동작하기 위해서는 별도의 작업이 필요하다.

  > 객체는 가급적 단반향 연관관계를 갖게끔 설계하는 것이 좋다.

  > mappedBy는 왜쓰죠?

    - 객체와 테이블 간 연관관계를 맺는 차이를 이해하면 쉽다.

    - 객체의 양방향 관계는 사실 서로 다른 단방향 관계 2개다.

    - 둘 중 하나로 외래 키를 관리해야 하는 경우에 연관관계의 주인을 설정한다.

    - 연관관계의 주인만이 외래키를 관리한다.

      - 주인은 주체이기 때문에 mappedBy를 사용하지 않는다.

      - 주인이 아닌쪽에는 mappedBy로 주인이 누구인지 지정해주어야 한다.

      - 주인은 외래키가 있는 곳으로 정해주는 것이 좋다. (외래키를 갖는 곳)

        - n:1 관계에서는 n쪽이 연관관계의 주인이다

 

4. 양방향 매핑시 주의점

  > 연관관계의 주인에 값을 입력하지 않음

    - 연관관계의 주인이 아닌곳에는 값을 입력하지 않아도 됨

    - 순수한 객체 관계를 고려하면 주인과 주인이 아닌 쪽 모두에 값을 넣어주는게 맞다.

  > 양방향 매핑 무한루프 조심

    - ex1) toString(), lombok : 필요에 의해 직접 만들어서 쓰기(자동완성 말고)

    - ex2) JSON 생성 라이브러리 : 컨트롤러에서 엔티티를 반환하면 안됨. 이것만 조심

  > [tip] 연관관계 편의 메소드 활용

    - 연관관계 주인에 연관관계 주인이 아닌 것을 넣을 때 연관관계 주인이 아닌 곳에 add

      - ex) 주인:Member에 team, 주인아님 : Team

@Entity
@Table(name = "MEMBER")
public class Member {

	.....
	@ManyToOne 
    @JoinColumn(name = "TEAM_ID")  
    private Team team; 
    .....

    public void changeTeam(Team team){
        this.team = team;
        team.getMembers().add(this);
    }
}

 

5. 연관관계 매핑 케이스

  > 다대일(N : 1) : 보통 가장 많이 사용됨

    - 객체에는 '다'쪽에 연관관계 주인이 있고, 테이블에는 '다' 쪽에 외래키가 있어야 함

    - 양방향 매핑을 하려면? : @OneToMany(mappedBy = "연관관계주인필드")

      - @ManyToOne에는 mappedBy속성이 없다.

  > 일대다(1 : N)

    - JPA 표준스펙에서 지원하기는 하지만 권장되지 않음

    - 객체에는 '일'쪽에 연관관계 주인이 있지만, 테이블에는 '다'쪽에 외래키가 있음

    - 일대다 양방향 매핑은 공식적으로 없음

  > 일대일(1 : 1)

    - 주 테이블에 외래키를 넣거나 대상 테이블에 외래키를 넣거나 선택 가능

    - 외래키에 UNIQUE 제약 조건이 있어야 문제발생 가능성이 낮음

    - 외래키가 있는 곳이 연관관계의 주인이다.

  > 다대다(N : M)

    - RDB는 정규화된 테이블 2개로 다대다 관계를 표현할 수 없음

      - 연결(중간) 테이블을 추가해서 일대다, 다대일 관계로 풀어야함

    - 객체는 컬렉션을 사용해서 객체 2개로 다대다 관계 표현 가능

    - @ManyToMany @JoinTable(name = "연결테이블이름")

    - 한계

      - 연결테이블에 수정이나 추가 작업이 불가능

      - 연결테이블이 숨겨져있기 때문에 알 수 없는 쿼리가 실행됨

    - 극복 : JPA에 위임하지 말고 중간엔티티를 생성해서 ManyToOne - OneToMany로 연결하면 좋다.

 

6. 상속관계 매핑

  > RDB에는 객체와 다르게 상속 개념이 없지만, 어느정도 유사한 슈퍼타입 서브타입 관계라는 모델링 기법이 있다.

  > 슈퍼타입 서브타입 논리모델을 실제 물리모델로 전환하는 방법

    - 조인 전략(정석) : 각각 테이블로 변환

      - @Inheritance(strategy = InheritanceType.JOINED)

      - 가장 정규화된 방식이며, 객체 상속 모델과 유사함

      - 장점 : 설계가 깔끔하고 저장공간 효율화

      - 단점 : 조회 시 조인을 많이 사용하므로 복잡도 증가 -> 큰 단점 아님

    - 단일 테이블 전략 : 한 테이블이 모든 컬럼을 포함

      - default, @Inheritance(strategy = InheritanceType.SINGLE_TABLE)

      - 장점 : 조회 쿼리가 단순하고 조회 성능이 좋음

      - 단점 : null을 허용해야 함

    - 구현 클래스 별 테이블 전략 : 서브타입 테이블로 변환

      - @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)

      - 검색 시 비효율 발생 가능성 있음

      - 안쓰는게 좋음

 

7. @MappedSuperclass(매핑관계 상속)

  > 공통 매핑 정보가 필요할 때 사용 (공통 속성)

    - ex) 모든 엔티티는 DB에 값을 저장할 떄 마다 저장시점과 주체를 저장해야하는 룰이 있는 경우

  > 활용방법

    - 공통 매핑 정보를 갖는 클래스(BaseEntity)를 만들고 @MappedSuperclass어노테이션 붙임

    - 공통 매핑정보를 가질 엔티티들은 BaseEntity를 상속받는다.(extends)

  > 특징

    - 엔티티가 아니므로 테이블과 매핑되지 않는다.

    - 자식클래스에 상속정보를 보내지 않으므로 자식클래스 객체를 부모타입으로 조회할 수 없다.

    - 추상클래스 사용 권장

 

 

 

Comments