연관관계의 종류는 다양한데 알맞은 연관관계를 매핑하기 위해 고려해야 할 사항은 3가지이다.
- 다중성
- 단방향, 양방향
- 연관관계의 주인
다중성
연관관계의 종류는 다음과 같다.
- 다대일: @ManyToOne
- 일대다: @OneToMany
- 일대일: @OneToOne
- 다대다: @ManyToMany
단방향, 양방향
테이블의 연관관계 매핑시 외래 키 하나로 양쪽 테이블을 조인하여 참조가 가능하기 때문에 방향의 개념이 존재하지 않는다.
하지만 객체의 연관관계 매핑시 참조용 필드가 있는 쪽으로만 참조가 가능하기 때문에 양쪽이 서로 참조하려면 양방향 연관관계를 맺어주어야한다.
연관관계의 주인
위와 같은 테이블과 객체의 차이때문에 ORM을 사용하여 객체를 테이블에 매핑할 때 테이블의 외래 키를 관리할 곳을 지정해주어야한다.
때문에 외래 키를 관리하는 객체를 연관관계의 주인이라 하고 주인의 반대편 객체는 외래키에 영향을 주지 않으며 단순 조회만 가능하다(양방향 시)
다대일 단방향 매핑
다대일 양방향 매핑
가장 많이 사용되는 양방향 매핑
양방향 매핑에서 외래키가 있는 쪽이 연관관계의 주인이고 다른 객체는 mappedBy를 사용하여 참조가 가능하도록 개발한다.
일대다 단방향 매핑
일대다 단방향 매핑
다대일 매핑에서 다(N)이 연관관계릐 주인이었던것과 달리 일대다 단방향 매핑에서는 일(1)이 연관관계의 주인이다.
테이블의 연관관계는 항상 외래키가 다(N)에 존재하기 때문에 일대다 단방향 매핑에서는 연관관계의 주인인 일(1)에서 반대편 테이블의 외래 키를 관리하는 특이한 구조를 가진다.
@JoinColumn을 꼭 사용하여야 하며 그렇지 않으면 조인 테이블 방식(중간 테이블을 사용하는 방식)을 사용한다.
연관관계 주인과 외래키를 가진 테이블이 다른 점 떄문에 연관관계 관리를 위해 추가로 UPDATE SQL을 실행해주어야 한다. 때문에 일대다 단방향 매핑보다는 다대일 양방향 매핑을 사용하도록 한다.
일대다 양방향매핑은 공식적으로 존재하지는 않으나 @JoinColumn(insertable=false, updatable=false)를 사용하여 구현이 가능하다. 읽기 전용 필드를 사용하여 양방향 처럼 사용하는 방법이지만 왠만해서는 다대일 양방향 매핑을 사용하도록 한다.
일대일 관계
일대일 관계는 그 반대도 일대일 관계이다.
주 테이블이나 대상 테이블 중에 외래 키 선택 가능
일대일 - 주 테이블에 외래 키 단방향 매핑
다대일 단방향 매핑과 유사하게 외래키가 존재하는 엔티티에 주인을 위치시켜 연관관계를 매핑한다.
일대일 - 주 테이블에 외래 키 양방향 매핑
다대일 양방향 매핑처럼 외래키가 있는 엔티티가 연관관계의 주인이다.
mappedBy를 사용하여 반대편에서도 참조가 가능하도록 구현
일대일 - 대상 테이블에 외래 키 단방향 매핑
단방향 관계는 JPA가 지원하지 않는다.
일대일 - 대상 테이블에 외래 키 양방향 매핑
일대일 주 테이블에 외래 키 양방향과 매핑 방법이 같음
일대일 정리
주 테이블에 외래 키
- 주 테이블에 외래 키
- 주 객체가 대상 객체의 참조를 가지는 것 처럼 주 테이블에 외래 키를 두고 대상 테이블을 찾음
- 객체지향 개발자 선호
- JPA 매핑 편리
- 장점: 주 테이블만 조회해도 대상 테이블에 데이터가 있는지 확인 가능
- 단점: 값이 없으면 외래 키에 null 허용
대상 테이블에 외래 키
- 대상 테이블에 외래 키가 존재
- 전통적인 데이터베이스 개발자 선호
- 장점: 주 테이블과 대상 테이블을 일대일에서 일대다 관계로 변경할 때 테이블 구조 유지
- 단점: 프록시 기능의 한계로 지연 로딩으로 설정해도 항상 즉시 로딩됨(프록시는 뒤에서 설명)
다대다
관계형 데이터베이스는 정규화된 테이블 2개로 다대다 관계를 표현할 수 없다.
때문에 연결 테이블을 추가하여 일대다, 다대일 관계로 풀어내야한다.
@ManyToMany를 사용하고 @JoinTable로 연결 테이블을 지정하여 두 엔티티 모두 컬렉션으로 선언하여 객체 2개로 다대다 관계가 가능하다.
하지만 이렇게 생성된 연결테이블은 객체로 존재하지 않기 때문에 만약 추후 추가 필드가 필요할 경우 해결할 수 없다.
ex) 위 연결 테이블 Member_Product에 주문시간, 수량 같은 데이터가 추가된다면
연결 테이블용 엔티티를 추가하여 해결이 가능하다.(객체로 존재하지 않던 연결 테이블을 엔티티로 승격)
두 테이블 사이의 연결 테이블용 엔티티를 각 엔티티와 @ManyToOne, @OneToMany를 사용하여 연관관계를 매핑시킨다.
ex) 위 상황에서 Member엔티티와 Product엔티티는 Member_Product엔티티를 @OneToMany를 사용하여 매핑하고
Member_Product엔티티는 각 두 엔티티를 @ManyToOne을 사용하여 매핑
연결 엔티티는 객체로 존재하기 때문에 추후에 필드가 추가가 가능하다.
'백엔드(Back End) > Spring' 카테고리의 다른 글
[TIL]20230829 - 쓰레드 풀 (0) | 2023.09.05 |
---|---|
[TIL]20230828 - 톰캣 튜닝 (0) | 2023.09.05 |
[TIL]20230821 - 엔티티 연관관계 설정 (0) | 2023.08.28 |
[TIL]20230819 - JPA와 ORM, 엔티티 매니저와 영속성 매니저 (0) | 2023.08.23 |
[TIL]20230818 - Redis 캐싱 전략 (0) | 2023.08.21 |