티스토리 뷰
양방향 연관관계
- 일반적으로 RDB는 방향이 존재하지 않음. 즉, 양방향이라는 개념 자체가 없음
- OneToMany를 사용하더라도 실질적으로 One 쪽의 DB에 컬럼이 생기지 않음
- 객체 단에서 편리함을 제공하기 위해 양방향 연관관계를 제공하는 것
- 따라서 JPA에서 양방향 연관관계를 사용할 경우 연관관계 주인을 정의해 줘야 함
- 연관관계의 주인인 Entity만 외래키의 값을 변경할 수 있고 상대방 Entity는 조회만 가능한 제약이 있음
- 양방향 연관관계를 설정하면 양쪽 모두에 참조 변수를 설정해 줘야 함(동기화 필요).
- 이러한 불편함을 해결하고자 연관관계 편의메소드를 활용
- 일반적으로 연관관계 편의 메소드는 주인 엔티티에 정의함(주인이 아닌 쪽에 정의해도 됨)
- 추후 유지보수나 확장 측면에서 단방향으로 설정하는 게 더 낫다
단방향 One-To-Many의 단점
- 내부적으로 join을 위한 테이블을 별도로 만듬(@JoinColumn를 사용하면 해결됨)
- One쪽에 참조 테이블을 Colleaction으로 두고 있어도, 실질적으로 DB에서 FK는 Many 쪽에 저장됨
- 실무에서 잘 사용하지 않는 방식
- One에서 Many객체가 바뀌면, DB의 Many 테이블에 업데이트 쿼리가 나가는 상황
- 즉, 단방향이므로 One이 연관관계 주인이지만 테이블에는 Many 쪽에 FK가 생성되는 불일치 문제 발생(객체와 테이블의 패러다임 불일치)
- 이러한 패러다임 불일치 문제 때문에 One을 수정했는데 Many쪽으로 Update 쿼리가 나가게 됨(FK위치 차이)
- 다대일 단방향 관계로 매핑하고, 필요할 경우 양방향 매핑을 통해서 해결함
- 양방향이 필요하다면 다대일 양방향으로 하자(연관관계 주인을 다쪽에 두어 패러다임 불일치 문제 해결)
- 그러나 최적은 다대일 단방향을 사용하는 것임
양방향 연관관계로 인해 생성된 연관관계 편의메소드의 단점
- 두 엔티티 간 동기화가 필요하게 됨
- 이러한 로직 자체가 불필요하지만 해줘야 할 경우가 많음
- 동기화를 맞춰주다보니 무한 참조 현상이 발생할 수 있음
- 시스템이 복잡도가 올라감(코드 가속성도 안 좋아짐)
cf. RDB와 JPA의 패러다임 불일치로 발생하는 문제: N+1 문제
- N+1 문제는 1대다 관계일 경우에 발생하는 문제이다. 결론부터 말하자면 OneToMany라는 관계가 RDB 개념에는 없기 때문인 건데, 결국엔 RDB와 JPA의 FK의 패러다임 불일치로 발생하는 문제라고 볼 수 있다.
- JPA의 쿼리메소드(예: findAll, findById) 특성상 join이 발생하는 쿼리를 만들 수 없기 때문에 부모 테이블 조회 1번 하고 자식 테이블에서 조회 1번 하는 쿼리가 총 N번 발생하기 때문에 생기는 문제이다. 즉, OneToMany라는 연관관계 때문이라는 것이다.
- 부모테이블 1건 자식테이블 10건이 있을 때 join 쿼리를 날리면 몇 건의 쿼리가 소요될까? 부모 엔티티를 조회하는 쿼리 1개와 자식엔티티 N개를 찾는 쿼리 N개(10개), 총 N+1개의 쿼리가 발생하기 때문에 N+1 문제이다.
- N+1 문제는 fetchType을 LAZY로 바꾼다고 해서 해결되지 않는다. LAZY 로딩은 단순히 연관 엔티티를 가져올 시점을 의미하기 때문이다.
- N+1 문제를 해결하기 위해선 JPQL의 fetch join 또는 직접 SQL join을 작성하여 해결해야 한다.
- N이 클수록 병목지점이 될 수 있다.
'[ 백엔드 개발 ] > [ Spring ]' 카테고리의 다른 글
[test] Controller 테스트와 MockMvc (0) | 2022.04.07 |
---|---|
<추천글>[JPA] CascadeType.REMOVE vs orphanRemoval true (0) | 2022.01.10 |
[JPA] Entity와 기본생성자, Proxy (0) | 2022.01.04 |
[spring] Bean 생성 순서와 Bean Life Cycle (빈 생명주기) (0) | 2021.12.14 |
[test] Test Double과 Mockito, BDDMockito 프레임워크 (0) | 2021.12.08 |
- Total
- Today
- Yesterday
- Controller
- Linux
- 코틀린
- 우분투
- LFCS
- ci/cd
- Java
- 컨트롤러
- golang
- kafka
- Stream
- spring
- github actions
- Non-Blocking
- docker
- 카프카
- GitOps
- Kotlin
- K8s
- CICD
- rolling update
- db
- ubuntu
- 쿠버네티스
- Kubernetes
- jvm
- RDB
- container
- go
- argocd
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |