[JPA 프로그래밍] 5. 다양한 연관관계 매핑
연관관계 매핑시 고려사항 3가지
다중성
엔티티의 연관관계를 매핑할 때 연관관계가 있는 두 엔티티가 일대일 관계인지 일대다 관계인지 다중성을 고려해야 한다.
- 다대일 : @ManyToOne
- 일대다 : @OneToMany
- 일대일 : @OneToOne
- 다대다 : @ManyToMany
단방향, 양방향
테이블은 외래 키 하나로 조인을 사용해서 양방향 쿼리가 가능하므로 사실 방향이라는 개념은 없다. 반면에 객체는 참조용 필드가 있는 쪽으로만 참조가 가능하기 때문에 방향이라는 개념이 존재한다. 한 쪽만 참조하면 단방향, 양쪽이 서로 참조하면 양방향이라고 한다.
연관관계의 주인
테이블은 외래 키 하나로 두 테이블이 연관관계를 맺는다. 객체 양방향 관계는 참조가 두 군데 존재한다. JPA는 두 객체 연관관계 중 하나를 정해서 데이터베이스 외래키를 관리하는데 이를 연관관계의 주인이라고 한다. 외래키를 가진 테이블과 매핑한 엔티티가 외래키를 관리하는 게 효율적이므로 보통 이곳을 연관관계의 주인으로 선택한다. 주인이 아닌 방향은 외래 키를 변경할 수 없고 조회만 가능하다
다대일 (N:1)
다대일 단방향
회원은 Member.team을 통해 팀 엔티티를 참조할 수 있지만, 팀 입장에서는 불가능하다. 따라서 회원과 팀은 다대일 단방향 관계이다.
- 다대일 단방향은 가장 많이 사용하는 연관관계이다.
다대일 양방향
회원은 Member.team을 통해 팀 엔티티를 참조할 수 있고, 팀도 Team.members를 통해 회원 엔티티를 참조할 수 있다. 회원과 팀은 다대일 양방향 관계이다
- 외래키가 있는 쪽이 연관관계의 주인이다
- 양쪽을 서로 참조하도록 개발한다.
일대다 (1:N)
일대다 단방향
팀 엔티티에서는 Team.members를 통해 회원 엔티티를 조회할 수 있다.
- 일대다 단방향은 일(1)이 연관관계의 주인이다
- 테이블 일대다 관계는 항상 다(N) 쪽에 외래 키가 있다
- 객체와 테이블의 차이 때문에 반대편 테이블의 외래키를 관리하는 특이한 구조이다.
- @JoinColumn을 꼭 사용해야 한다
[단점]
1. 엔티티가 관리하는 외래 키가 다른 테이블에 있음
2. 연관관계 관리를 위해 추가로 UPDATE SQL을 실행
=> 일대다 단방향 매핑보다는 다대일 양방향 매핑을 사용하자
일대다 양방향
팀 엔티티에서는 Team.members를 통해 회원 엔티티를 조회할 수 있다. 그리고 회원 엔티티에서도 Member.team을 통해 팀 엔티티를 조회 가능하다.
- 이러한 매핑은 공식적으로 존재하지 않는다
- @JoinColumn(insertable=false, updatable=false)를 통해 연관관계의 주인을 하나로만 설정하자
- 읽기 전용 필드를 사용해서 양방향처럼 사용하는 방법이다
일대일 (1:1)
일대일 관계에서는 외래키에 데이터베이스 유니크(UNI) 제약 조건을 추가해야 한다.
일대일 : 주 테이블에 외래키 단방향
다대일(@ManyToOne) 단방향 매핑과 유사하다.
일대일 : 주 테이블에 외래키 양방향
다대일 양방향 매핑처럼 외래키가 있는 곳이 연관관계의 주인이다. 반대편은 mappedBy를 적용시켜야 한다.
일대일 : 대상 테이블에 외래키 단방향
단방향 관계는 JPA가 지원하지 않는다.
일대일 : 대상 테이블에 외래키 양방향
일대일 주 테이블에 외래키 양방향과 매핑 방법이 동일하다
정리
1. 주 테이블에 외래 키
- 주 객체가 대상 객체의 참조를 가지는 것처럼 주 테이블에 외래키를 두고 대상 테이블을 찾음
- 객체 지향 개발자 선호
- JPA 매핑 편리
- 장점 : 주 테이블만 조회해도 대상 테이블에 데이터가 있는지 확인 가능
- 단점 : 값이 없으면 외래키에 null 허용
2. 대상 테이블에 외래 키
- 대상 테이블에 외래키가 존재
- 전통적인 데이터베이스 개발자 선호
- 장점 : 주 테이블과 대상 테이블을 일대일에서 일대다 관계로 변경할 때 테이블 구조 유지
- 단점 : 프록시 기능의 한계로 지연로딩을 설정해도 항상 즉시 로딩됨
다대다 (N:M)
다대다
관계형 데이터베이스는 정규화된 테이블 2개로 다대다 관계를 표현할 수 없다. 연결 테이블을 추가해서 일대다, 다대일 관계로 풀어내야 한다.
- @ManyToMany 사용
- @JoinTable로 연결 테이블 지정
- 다대다 매핑 : 단방향, 양방향 가능
다대다 매핑의 한계
편리해 보이지만, 실무에서는 사용하지 않는다. 연결 테이블이 단순히 연결만 하고 끝나지 않는다.
주문 시간, 수량이 같은 데이터가 들어올 수도 있다.
다대다 한계 극복
연결 테이블용 엔티티를 추가하면 된다.
@ManyToMany를 @OneToMany, @ManyToOne으로!