연관관계 방향 설정에 따른 트레이드 오프
연관관계 매핑
다양한 연관관계 매핑이 존재하며, 실무에서 어떤 연관관계 매핑을 사용할 것인지에 따라서 객체의 설계가 달라진다.
다대일(N:1)
다대일(N:1) 연관관계 매핑은, @ManyToOne 을 사용하는 곳을 연관관계 주인으로 설정하는 것을 말한다. 실무에서 가장 자주 사용되고 추천하는 방식
이라고 한다. 이 방식의 장점은 객체의 형태를 최대한 관계형 데이터베이스와 유사하게 가져가기 때문에 유지보수성이 좋다는 점이다.
단점은, Member 에서 Team 으로 참조할 일이 없더라도 다대일 연관관계 매핑을 사용하기 위해서, 참조 변수를 두는 점이다. 객체지향적으로 조금 손해 보더라도, 객체를 관계형 데이터베이스와 유사하게 가져갔을 때의 장점이 더 크기 때문에 실무에서 자주 사용하는 방식이라고 한다.
@NoArgsConstructor
@Getter
@Entity
@Table(name = "member")
public class Member {
// 생략
@JoinColumn(name = "team_id")
@ManyToOne
private Team team;
}
@NoArgsConstructor
@Getter
@Entity
@Table(name = "team")
public class Team {
// 생략
@OneToMany(mappedBy = "team")
private List<Member> members = new ArrayList<>();
}
일대다(1:N)
일대다 단방향은 @OneToMany 를 사용하는 곳을 연관관계 주인으로 설정하는 것을 말한다.
테이블 관점에서는 항상 다(N) 쪽에 외래키가 존재하기 때문에, 객체 입장에서는 반대편 테이블의 외래 키를 관리하게 되는 구조이다.
실무에서는 일대다보다 다대일 단방향 관계를 자주 사용한다.
@NoArgsConstructor
@Getter
@Entity
@Table(name = "team")
public class Team {
// 생략
@JoinColumn(name = "team_id")
@OneToMany
private List<Member> members = new ArrayList<>();
}
@JoinColumn 을 사용하지 않으면, Team_Member
라는 임의의 테이블(조인 테이블)을 생성하여 조회하기 때문에, 중간 테이블이 하나 생기면 실무에서 운영하기도 쉽지 않기 때문에 @JoinColumn 를 꼭 사용해야 한다.
일대다(1:N) 단방향 연관관계 매핑 정리
- 엔티티가 관리하는 외래키가 다른 테이블에 존재
- 연관관계 관리를 위해 추가로 UPDATE SQL 실행
- 외래키 UPDATE SQL
- Default : @JoinTable 전략
- 일대다(1:N) 를 사용할 것이면, @JoinColumn 을 사용하여 JoinTable 을 생성하지 않는 전략을 사용하는 것을 추천
- 일대다보다는 다대일(N:1) 단방향 연관관계 매핑을 사용하는 것을 추천
일대일(1:1)
- 주 테이블이나 대상 테이블 중 외래키 선택 가능
- 주 테이블 : 데이터 조회가 빈번하게 일어나는 테이블(Ex. Member)
- 외래키에 데이터베이스 유니크 제약조건 추가
- FK 에 유니크 제약조건이 걸려있어야 1:1 이 유지가 된다.
- Ex. 헬스장 회원과 사물함의 관계
- 회원은 사물함을 딱 한 개만 가질 수 있다.
- 회원(Member) or 사물함(Locker) 둘 중 한 곳에서만
유니크 제약조건이 걸린 FK
가 존재하면 된다.
- 다대일과 유사
@NoArgsConstructor
@Getter
@Entity
@Table(name = "member")
public class Member {
@Column(name = "member_id", length = 20)
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Id
private Long id;
@JoinColumn(name = "locker_id")
@OneToOne
private Locker locker;
}
```java
@NoArgsConstructor
@Getter
@Entity
@Table(name = "locker")
public class Locker {
@Column(name = "locker_id", length = 20)
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Id
private Long id;
@OneToOne(mappedBy = "locker")
private Member member;
}
일대일(1:N) 연관관계 매핑 정리
주 테이블에 외래키가 존재하는 경우
- 객체지향 개발자가 선호하는 방식
- 장점 : 주 테이블이 데이터 조회가 빈번하게 일어나므로, 주 테이블을 한 번만 조회하면, 대상 테이블에 대한 정보도 같이 있어서 쿼리 한방으로 해결 가능
- JPA 매핑이 편리
- 단점 : 값이 없으면 외래 키에 NULL 을 허용해야 함
- Ex. Locker 를 가지고 있지 않은 회원도 존재할 수 있기 때문이다.
대상 테이블에 외래키가 존재하는 경우
- DBA 가 선호하는 방식
- 장점 : 회원이 여러개의 Locker 를 가지게 되는 경우, FK 의 유니크 제약조건을 제거하고 다대일 연관관계로 변경하면 된다.
- 단점 : 양방향으로 만들어야 한다. 지연 로딩으로 설정해도 항상 즉시 로딩 된다.
실무에서는 주 테이블에 외래키가 존재하는 경우를 사용하는 것이 개발자 입장에서는 편한데, 일대일 연관관계 매핑에서는 DBA 가 존재한다면 충분한 협의가 이루어 져야 한다.
다대다(N:M)
- 실무에서 사용하면 안되는 방식
- 다대다 관계에서는 중간 테이블(연결 테이블)을 추가해서 일대다, 다대일로 풀어내야 한다.
References
'JPA' 카테고리의 다른 글
프록시 객체와 영속성 컨텍스트 (0) | 2022.01.05 |
---|---|
테이블과 컬럼에 대한 명세를 엔티티에 자세하게 적는것이 좋은지? (0) | 2021.12.29 |
AllocationSize 를 통한 성능 최적화 (0) | 2021.12.28 |
기본키 매핑 전략에 따른 INSERT QUERY 실행 시점 (0) | 2021.12.28 |
EntityManager 를 쓰레드간 공유하면 안되는 이유 (0) | 2021.12.28 |