Chapter 5: 연관관계 매핑 기초

1. 단방향 연관 관계

객체 연관관계와 테이블 연관관계의 가장 큰 차이

  • 참조를 통한 연관관계는 언제나 단방향이다

    • 객체간에 양방향 으로 만들고 싶으면 반대쪽에도 필드를 추가해서 참조를 보관해야한다

      • 결국 연관관계를 하나 더 만들어야 한다

    • 이렇게 양쪽에서 서로 참조하는 것을 양방향 연관관계라 한다

      • 하지만 정확히 이야기하면, 이것은 양방향 관계가 아니라 서로 다른 단방향 관계 2개

      • 반면, 테이블은 외래 키 하나로 양방향으로 조인할 수 있다

객체 연관관계 vs 테이블 연관관계

  • 객체

    • 참조 (주소) 로 연관관계를 맺는다

    • 연관된 데이터를 참조 를 사용해 조회한다

      • 연관관계를 참조를 사용해서 탐색하는 것을 객체 그래프 탐색 이라 한다

    • 참조를 사용하는 객체의 연관관계는 단방향 이다

      • 객체를 양방향으로 참조하려면, 단방향 연관관계를 2개 만들어야 한다

  • 테이블

    • 외래 키 로 연관관계를 맺는다

    • 연관된 데이터를 JOIN 을 통해 조회한다

      • 외래 키를 사용해서 연관관계를 탐색하는 것을 JOIN 이라 한다

    • 외래 키를 사용하는 테이블의 연관관계는 양방향 이다

@JoinColumn

  • 외래 키를 매핑할 때 사용한다

  • 속성

    속성기능기본값

    name

    매핑할 외래 키 이름을 지정한다

    필드명 + _ + 참조하는 테이블의 기본 키 컬럼명

    referencedColumnName

    외래 키가 참조하는 대상 테이블의 컬럼명

    차모하는 테이블의 기본 키 컬럼명

    foreignKey (DDL)

    외래 키 제약조건을 직접 지정할 수 있다 (이 속성은 테이블을 생성할 때만 사용!)

    unique , nullable , insertable , updatable, columnDefinition, table

    @Column 의 속성과 같다

  • @JoinColumn 생략

    • 해당 어노테이션을 생략하면 외래 키를 찾을 때 기본 전략을 사용한다

    • 기본 전략

      • 필드명 + _ + 참조하는 테이블의 컬럼명

@ManyToOne

  • 이름 그대로 다대일 (N:1) 관계라는 매핑 정보다

  • 연관관계를 매핑할 때 이렇게 다중성을 나타내는 어노테이션을 필수로 사용해야 한다

  • 속성

    속성기능기본값

    optional

    false로 설정하면 연관된 엔티티가 항상 있어야 한다

    true

    fetch

    global fetch 전략을 설정

    FetchType.EAGER

    cascade

    영속성 전이 기능을 사용

    targetEntity

    연관된 엔티티의 타입 정보를 설정한다 (이 기능은 거의 사용하지 않는다! 컬렉션을 사용해도 제네릭으로 타입 정보를 알 수 있기 때문!)

2. 연관관계 사용

2-1. 저장

  • JPA에서 엔티티를 저장할 때 연관된 모든 엔티티는 영속 상태 여야 한다

  • JPA는 참조한 객체의 식별자외래 키 로 사용해서 적절한 등록 쿼리 를 생성한다

2-2. 조회

연관관계가 있는 엔티티를 조회하는 방법

  1. 객체 그래프 탐색

    • 객체 연관관계를 사용한 조회

  2. 객체지향 쿼리 사용 (JPQL)

    • 예를 들어 회원을 대상으로 조회하는데 팀1에 소속된 회원만 조회하려면, 회원과 연관된 팀 엔티티를 검색 조건으로 사용해야 한다

      • SQL은 연관된 테이블을 JOIN 해서 검색조건을 사용하면 된다

      • JPQL도 JOIN을 지원한다 (문법은 약간 다름!)

    • JPQL은 객체(엔티티)를 대상으로 하고, SQL보다 간결하다

2-3. 수정

  • 수정은 em.update() 같은 method가 없다

  • 단순히 불러온 엔티티의 값만 변경해두면, 트랜잭션을 커밋 할 때 플러시 가 일어나면서 변경 감지 기능이 작동한다

    • 그리고 변경사항을 데이터베이스에 자동으로 반영한다

  • 연관관계를 수정할 때도 같은데, 참조하는 대상 만 변경하면 나머지는 JPA가 자동으로 처리한다

2-4. 연관관계 제거

: 연관관계를 null로 설정

2-5. 연관된 엔티티 삭제

  • 연관된 엔티티를 삭제하려면 기존에 있던 연관관계를 먼저 제거하고 삭제해야 한다

    • 그렇지 않으면 외래 키 제약조건으로 인해, DB에서 오류가 발생한다

3. 양방향 연관관계

  • 데이터베이스 테이블은 외래 키 하나로 양방향으로 조회할 수 있다

  • 객체는 연관관계가 맺어진 반대 방향에서도 접근할 수 있게, 컬렉션@OneToMany 매핑 정보, 그리고 mappedBy 속성을 사용한다

    • ex)

      • 회원 → 팀 (Member.team)

      • 팀 → 회원 (Team.members)

        • 여기서 members는 list

  • mappedBy 속성은 양방향 매핑일 때 사용하는데, 반대쪽 매핑의 필드 이름을 값으로 주면 된다

4. 연관관계의 주인

  • mappedBy 가 필요한 이유

    • 테이블은 외래 키 하나로 두 테이블의 연관관계를 관리

    • 엔티티를 단방향으로 매핑하면 참조를 하나만 사용하므로 이 참조로 외래키를 관리하면 됨

    • but, 엔티티를 양방향으로 매핑하면 양쪽에서 서로를 참조하게 됨

      • 따라서 객체의 연관관계를 관리하는 포인트는 2곳으로 늘어난다

      • 객체의 참조는 둘인데, 외래 키는 하나다

    • 이러한 차이로 인해 JPA에서는 두 객체 연관 관계 중 하나를 정해서 테이블의 외래 키를 관리해야 하는데, 이것을 연관관계의 주인 이라 한다

  • 연관관계의 주인

    • 연관관계의 주인만이 DB 연관관계와 매핑되고, 외래키를 관리할 수 있다

      • 주인이 아닌 쪽은 읽기만 할 수 있다

    • 주인은 mappedBy 속성을 사용하지 않는다

      • 주인이 아니면 mappedBy 속성을 사용해서 속성의 값으로 연관관계의 주인지정해야 한다

    • 연관관계의 주인을 정한다는 것은 외래 키 관리자를 선택하는 것이다

      • 연관관계의 주인은 외래 키가 있는 곳을 뜻한다

      • 연관관계의 주인만 데이터베이스 연관관계와 매핑되고, 외래 키를 관리할 수 있다

      • 주인이 아닌 반대편은 읽기만 가능하고, 외래키를 변경하지는 못한다

5. 양방향 연관관계 저장

  • 양방향 연관관계는 연관관계의 주인이 외래 키를 관리한다

    • 따라서 주인이 아닌 방향은 값을 설정하지 않아도 데이터베이스에 외래 키 값이 정상 입력된다

6. 양방향 연관관계 주의점

  • 양방향 연관관계를 설정하고 가장 흔히 하는 실수는, 연관관계의 주인에는 값을 입력하지 않고, 주인이 아닌 곳에만 값을 입력하는 것이다

    • 연관관계의 주인만이 외래 키변경할 수 있다는 것을 기억하자!

6-1. 순수한 객체까지 고려한 양방향 연관관계

  • 연관관계의 주인에만 값을 저장하고 주인이 아닌 곳에는 값을 저장하지 않는 것이 아니라, 객체 관점 에서 양쪽 방향에 모두 값을 입력해주는 것이 가장 안전하다

    • 양쪽 방향 모두 값을 입력하지 않으면 JPA를 사용하지 않는 순수한 객체 상태에서 심각한 문제가 발생할 수 있다

  • 결론

    • 객체의 양방향 연관관계는 양쪽 모두 관계를 맺어주자!

6-2. 연관관계 편의 메소드

  • 연관관계 설정 method를 각각 호출하다 보면 실수로 둘 중 하나만 호출해서 양방향이 깨질 수 있다

    • 양방향 관계에서 두 코드는 하나인 것처럼 사용하는 것이 안전한다

  • 한 번에 양방향 관게를 설정하는 method를 연관관계 편의 method 라 한다

7. 정리

  • 단방향 매핑과 비교해서 양방향 매핑은 복잡하다

    • 연관관계의 주인도 정해야 하고, 두 개의 단방향 연관관계를 양방향으로 만들기 위해 로직도 잘 관리해야 한다

    • 중요한 사실은 연관관계가 하나인 단방향 매핑은 언제나 연관관계의 주인이라는 점이다!

      • 양방향은 여기에 주인이 아닌 연관관계를 하나 추가했을 뿐이다

    • 결국 단방향과 비교해서 양방향의 장점은 반대 방향으로 객체 그래프 탐색 기능이 추가된 것 뿐이다

  • 단방향 매핑만으로 테이블과 객체의 연관관계 매핑은 이미 완료되었다

  • 단방향을 양방향으로 만들려면 반대방향으로 객체 그래프 탐색 기능이 추가된다

  • 양방향 연관관계를 매핑하려면 객체에서 양쪽 방향모두 관리해야 한다

  • 양방향 매핑은 복잡하다

    • 우선 단방향 매핑을 사용하고, 반대 방향으로 객체 그래프 탐색 기능(JPQL 쿼리 탐색 포함)이 필요할 때 양방향을 사용하도록 코드를 추가해도 된다

Last updated