1. 연관관계 매핑의 종류
연관 관계 매핑의 종류는 다음과 같이 4가지입니다.
- 다대일 : @ManyToOne
- 일대다 : @OneToMany
- 일대일 : @OneToOne
- 다대다 : @ManyToMany
2. 다대일 연관관계
다대일 단방향은 가장 많이 사용하는 연관 관계입니다. 외래 키가 있는 쪽이 연관계의 주인이고 양쪽을 서로 참조하도록 개발합니다.
3. 일대다 연관관계
일대다 단방향은 일대다에서 일(1)이 연관관계의 주인입니다. 테이블 일대다 관계는 항상 다(N)쪽에 외래키가 있습니다. 객체와 테이블의 차이 때문에 반대편 테이블의 외래키를 관리하는 특이한 구조입니다. @JoinColumn을 꼭 사용해야합니다. 그렇지 않으면 조인 테이블 방식을 사용하여 중간에 테이블을 하나 추가합니다.
팀의 Members값을 바꿨을 때 MEMBER이라는 다른 테이블의 값을 관리하게됩니다. 그래서 업데이트 쿼리가 추가로 나가게 됩니다. 이 관계의 심각한 점은 내 입장에서는 team만 손댄거 같은데, 왜 member 테이블이 업데이트 되지라고 생각할 수 있습니다.
또한 실무에서는 테이블이 한두개가 아니기 때문에 운영이 매우 힘들어집니다. 그래서 일대다 단방향 매핑보다는 다대일 단방향관계, 필요하면 양방향 추가를 사용하는 방식을 택합니다.
[일대다 양방향]
일대다 양방향이라는 매핑은 공식적으로 존재하지 않습니다. 하지만 만들어 줄 수 있습니다.
@JoinColumn(insertable=false, updatable=false)
읽기 전용 필드를 사용해서 양방향 처럼 사용할 수 있습니다. 이런 매핑 보다는 다대일 양방향을 사용합시다.
4. 일대일 연관관계
일대일 관계는 그 반대도 일대일입니다. 주 테이블이나 대상 테이블 중에 외래키를 선택가능합니다. 다대일 단방향 매핑과 유사합니다. 다대일 양방향 매핑처럼 외래키가 있는 곳이 연관관계의 주인이고 반대편은 mappedBy를 적용해줍니다.
다음 모델은 일대일 대상 테이블에 외래키 단방향을 나타냅니다. 이거는 지원하지 않습니다. 일대일은 내 Entity에 있는 외래키를 직접 관리해야합니다.
대신 양방향 관계는 지원합니다.
여기서 데이터베이스적으로 하나 따져보겠습니다. 운영하는 입장과 DBA의 관점 차이입니다. DB만 생각했을때 만약 시간이 지나서 MEMBER 가 여러개의 LOCKER를 가지면 바로위의 그림이 바꾸기가 쉽습니다.
그런데 반대로 비즈니스가 뒤집어져서, 하나의 LOCKER가 여러개의 MEMBER를 가질 수 있으면 MEMBER가 LOCKER_ID를 갖는게 더 적합합니다. 이제 개발자 입장에서보면, MEMBER에 LOCKER가 있는게 성능이나 여러가지 장점이 있습니다. 내가 MEMBER를 많이 조회하면, 이미 LOCKER값이 있기 때문에 LOCKER를 판단하는게 쉬워집니다. 하지만 DBA는 MEMBER가 LOCKER_ID를 갖고있는 것을 싫어할 수도 있습니다.
[일대일 정리]
주 테이블에 외래 키
- 주 객체가 대상 객체의 참조를 가지는 것 처럼 주 테이블에 외래 키를 두고 대상 테이블을 찾음
- 객체지향 개발자 선호
- JPA 매핑 편리
- 장점: 주 테이블만 조회해도 대상 테이블에 데이터가 있는지 확인 가능
- 단점: 값이 없으면 외래 키에 null 허용
대상 테이블에 외래 키
- 대상 테이블에 외래 키가 존재
- 전통적인 데이터베이스 개발자 선호
- 장점: 주 테이블과 대상 테이블을 일대일에서 일대다 관계로 변경할 때 테이블 구조 유지
- 단점: 프록시 기능의 한계로 지연 로딩으로 설정해도 항상 즉시 로딩됨(프록시는 뒤에서 설명)
- JPA가 제공하는 기본 프록시 기능이 한계가 있습니다. 지연로딩 설정해도 항상 즉시 로딩되는 경우가 있습니다. LOCKER에 MEMBER_ID가 있을때, MEMBER만 조회해서는 Member에 locker가 있는지 알 수 없습니다. LOCKER 테이블을 조회해야합니다. LOCKER테이블에 값이 있는지 없는지 확인을 해야합니다. 어차피 쿼리를 DB에 날려봐야 NULL인지 아닌지 알 수 있기 때문에 지연로딩 그냥 안하고 쿼리를 내보냅니다.
5. 다대다 연관관계
관계형 데이터베이스는 정규화된 테이블 2개로 다대다 관계를 표현할 수 없습니다. 연결 테이블을 추가해서 일대다, 다대일 관계로 풀어내야합니다. 그리고 이 모델은 실무에서 사용하지 않습니다.
객체는 아래와 같이 다대다 관계가 가능합니다.
- @ManyToMany 사용
- @JoinTable로 연결 테이블 지정
- 다대다 매핑: 단방향, 양방향 가능
편리해 보이지만 실무에서는 사용하지 않습니다. 연결 테이블이 단순히 연결만하고 끝나지 않습니다. 보통 추가데이터가 들어오는데 그게 안됩니다. 매핑정보만 들어가고 추가정보가 안들어갑니다. 그리고 중간 테이블이 숨겨져 있어서 쿼리가 생각하지 못한게 나옵니다.
그렇기 때문에 중간 테이블을 Entitiy로 만듭니다. 왠만하면 PK는 의미없는 값을 써야합니다. id가 어디에 종속되는식으로 걸리면 시스템의 유연성을 갈아치기가 쉽지 않습니다. Generate value로 쭉 쓰는 것을 권장합니다. 그래야 유연성이 조금더 커집니다. 비즈니스적으로 의미가 없는 값이지만, pk가 바뀌면 추가를 많이하게 됩니다. 필요하면 제약조건을 추가하면됩니다.
6. 애노테이션 주요 속성
REFERENCE
https://www.inflearn.com/course/ORM-JPA-Basic
'JPA' 카테고리의 다른 글
[JPA] @MappedSuperclass 애노테이션 (0) | 2020.04.19 |
---|---|
[JPA] 상속 관계 매핑(고급매핑) (0) | 2020.04.19 |
[JPA] 연관관계 매핑 기초 (0) | 2020.04.14 |
[JPA] 기본 키 매핑 (0) | 2020.04.10 |
[JPA] 객체와 테이블 매핑 (0) | 2020.04.10 |