반응형
Notice
Recent Posts
Recent Comments
관리 메뉴

간단한 개발관련 내용

5장 연관관계 매핑의 기초 본문

IT 책/JPA (ORM 표준 JPA 프로그래밍)

5장 연관관계 매핑의 기초

vincenzo.dev.82 2024. 11. 19. 13:41
반응형

객체의 참조와 테이블의 외래 키를 매핑하는 것이 이 장의 목표다

  • 방향(Direction)
  • 다중성(Multiplicity)
  • 연관관계 주인(Owner)

5.1 단방향 연관관계

  • 회원과 팀
    • 회원과 팀이 있다
    • 회원은 하나의 팀에만 소속될 수 있다
    • 회원과 팀은 다대일 관계다
  • 객체 연관관계
  • 테이블 연관관계
  • 객체 연관관계와 테이블 연관관계의 가장 큰 차이
    • 참조는 단방향이라 양방향을 하려면 서로 참조해야 한다. 그러나 이것은 양방향 관계가 아니라 서로 다른 단방향 관계 2개이다
  • 객체 연관관계 vs 테이블 연관관계 정리
    • 객체는 참조로 연관관계
    • 테이블은 외래 키를 사용하여 조인으로 연관관계

5.1.1 순수한 객체 연관관계

  • 객체 그래프 탐색이 가능

5.1.2 테이블 연관관계

  • 테이블은 외래 키를 사용하여 조인으로 연관관계

5.1.3 객체 관계 매핑

  • 회원과 팀은 @ManyToOne

5.1.4 @JoinColumn (172page) !!!!!!! 확인필요

<aside> 💡

@JoinColumn 생략

다음처럼 @JoinColumn을 생략하면 외래 키를 찾을 때 기본 전략을 사용한다.

@ManyToOne

private Team team;

  • 기본 전략 : 필드명 +_+참조하는 테이블의 컬럼명
  • 필드명(team) +_+참조하는 테이블의 컬럼명 </aside>

5.1.5 @ManyToOne

  • optional
    • false로 설정하면 연관된 엔터티가 항상 있어야 한다
  • fetch
    • FetchType.EAGER, FetchType.LAZY
  • cascade
    • 영속성전이
  • targetEntity
    • 엔터티 타입 정보

5.2 연관관계 사용

5.2.1 저장

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

5.2.2 조회

  • 객체 그래프 탐색(객체 연관관계를 사용한 조회)
  • 객체 지향 쿼리 사용: JPQL
    • em.createQuery(sql, Member.class);

5.2.3 수정

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

5.2.4 연관관계 제거

  • 참조에 null

5.2.5 연관된 엔터티 삭제

  • em.remove()

5.3 양방향 연관관계

  • 회원에서 팀은 일대다 이기 때문에 여러 건과 연관관계를 맺을 수 있으므로 컬렉션을 사용해야 한다.
    • 회원 —> 팀 (Member.team)
    • 팀 —> 회원 (Team.members)
  • JPA는 List를 포함해서 Collection, Set, Map 같은 다양한 컬렉션을 지원한다.
  • 데이터베이스 테이블은 외래 키 하나로 양방향으로 조회할 수 있다

5.3.1 양방향 연관관계 매핑

  • @ManyToOne
  • @OneToMany(mappedBy = “team”)

5.3.2 일대다 컬렉션 조회

 

5.4 연관관계 주인

  • @OneToMany는 직관적으로 이해가 될 것이다. 문제는 mappedBy 속성이다.
  • 테이블은 외래 키 하나로 두 테이블의 연관관계를 관리
  • 엔터티를 양방향 연관관계로 설정하면 객체의 참조는 둘인데 외래 키는 하나
  • 이런 차이로 인해 JPA에서는 두 객체 연관관계 중 하나를 정해서 테이블의 외래 키를 관리해야 하는데 이것을 연관관계의 주인이라 한다

5.4.1 양방향 매핑의 규칙: 연관관계의 주인

  • 양방향 연관관계 매핑 시 지켜야 할 규칙이 있는데 두 연관관계 중 하나를 연관관계의 주인으로 정해야 한다. 연관관계의 주인만이 데이터베이스 연관관계와 매핑되고 외래 키를 관리(등록, 수정, 삭제)할 수 있다. 반면에 주인이 아닌 쪽은 읽기만 할 수 있다.
  • 연관관계 주인을 정한다는 것은 사실 외래 키 관리자를 선택하는 것이다

5.4.2 연관관계의 주인은 외래 키가 있는 곳

  • 연관관계의 주인만 데이터베이스 연관관계와 매핑되고 외래 키를 관리할 수 있다. 주인이 아닌 반대편(inverse, non-owning side)은 읽기만 가능하고 외래 키를 변경하지는 못한다.

<aside> 💡

데이터베이스 테이블의 다대일, 일대다 관계에서는 항상 다 쪽이 외래 키를 가진다. 다 쪽인 @ManyToOne은 항상 연관관계의 주인이 되므로 mappedBy를 설정할 수 없다. 따라서 @ManyToOne에는 mappedBy 속성이 없다.

</aside>

 

5.5 양방향 연관관계 저장

  • 양방향 연관관계는 연관관계의 주인이 외래 키를 관리한다. 따라서 주인이 아닌 방향은 값을 설정하지 않아도 데이터베이스에 외래 키 값이 정상 입력된다
  • 팀을 통해 멤버가 추가되는 것은 데이터베이스에 저장할 때 무시된다
    • team.getMembers().add(member); // 무시(연관관계의 주인이 아님)

 

5.6 양방향 연관관계의 주의점

  • 다시 한 번 강조하지만 연관관계의 주인만이 외래 키의 값을 변경할 수 있다

5.6.1 순수한 객체까지 고려한 양방향 연관관계

  • 객체 관점에서 양쪽 방향 모두 값을 입력해주는 것이 가장 안전하다
  • 결론: 객체의 양방향 연관관계는 양쪽 모두 관계를 맺어주자?? 음??
  • 한 트랜잭션 안에서 연관관계의 주인에만 설정을 하고 반대편 객체에서 조회를 할 경우 조회되지 않는데 그런 것 때문에 양방향 연관관계 셋팅을 한다
  • 테스트케이스에서 연관관계 문제가 나올 수도 있고~

5.6.2 연관관계 편의 메서드

  • changeTeam(Team team) { … }
  • 한 번에 양방향 관계를 설정하는 메서드를 연관관계 편의 메서드라고 한다

5.6.3 연관관계 편의 메서드 작성 시 주의 사항

  • member의 팀을 변경할 경우, 기존 팀과 회원의 연관관계를 삭제하는 코드를 추가해야한다

<aside> 💡

…(중략)

문제는 관계를 변경하고 영속성 컨텍스트가 아직 살아있는 상태에서 teamA의 getMembers()를 호출하면 member1이 반환된다는 점이다. 따라서 변경된 연관관계는 앞서 설명한 것처럼 관계를 제거하는 것이 안전하다.

</aside>

 

5.7 정리

  • 양방향의 장점은 반대방향으로 객체 그래프 탐색 기능이 추가된 것뿐이다.
  • 주인의 반대편은 mappedBy로 주인을 지정해야 한다. 그리고 주인의 반대편은 단순히 보여주는 일(객체 그래프 탐색)만 할 수 있다.

내용을 정리하면 다음과 같다

  • 단방향 매핑만으로 테이블과 객체의 연관관계 매핑은 완료되었다
  • 단방향을 양방향으로 만들면 반대방향으로 객체 그래프 탐색 기능이 추가된다
  • 양방향 연관관계를 매핑하려면 객체에서 양쪽 방향 모두 관리해야 한다

<aside> 💡

연관관계의 주인을 정하는 기준

단방향은 항상 외래 키가 있는 곳을 기준으로 매핑하면 된다. …(중략) 비즈니스 중요도를 배제하고 단순히 외래 키 관리자 정도의 의미만 부여해야 한다.

</aside>

양방향 매핑 시 무한루프를 조심하자

  • toString(), lombok, JSON 생성 라이브러리

<aside> 💡

양방향 매핑 시에는 무한 루프에 빠지지 않게 조심해야 한다. 예를 들어 Member.toString()에서 getTeam()을 호출하고 Team.toString()에서 getMember를 호출하면 무한 루프에 빠질 수 있다. 이런 문제는 엔터티를 JSON으로 변환할 때 자주 발생하는데 JSON 라이브러리들은 보통 무한루프에 빠지지 않도록 하는 어노테이션이나 기능을제공한다.

</aside>

 

양방향 매핑 정리

  • 단방향 매핑만으로도 이미 연관관계 매핑은 완료
  • 양방향 매핑은 반대 방향으로 조회(객체 그래프 탐색) 기능이 추가된 것 뿐
    • 데이터 조회를 위해 양방향을 하는 것
  • JPQL에서 역방향으로 탐색할 일이 많음
  • 단방향 매핑을 잘 하고 양방향은 필요할 때 추가해도 됨

실전 예제 | 2. 연관관계 매핑 시작


 

페이지 요약


연관관계 매핑의 기본 개념

  • 객체의 참조와 테이블의 외래 키를 매핑하는 것이 이 장의 목표이다
  • 객체는 참조로, 테이블은 외래 키를 사용하여 조인으로 연관관계를 맺는다

단방향과 양방향 연관관계

  • 단방향 연관관계에서는 @ManyToOne과 @JoinColumn을 사용하여 매핑한다
  • 양방향 연관관계에서는 연관관계의 주인을 정해야 하며, 주인만이 외래 키를 관리할 수 있다
  • 연관관계의 주인은 외래 키가 있는 쪽(다쪽)이 되어야 한다

연관관계 사용 시 주의사항

  • 객체의 양방향 연관관계는 양쪽 모두 관계를 맺어주는 것이 안전하다
  • 연관관계 편의 메서드를 사용하여 양방향 관계를 한 번에 설정할 수 있다
  • 양방향 매핑 시 무한 루프에 빠지지 않도록 주의해야 한다
반응형