<추천글>[JPA] 연관관계 핵심 정리 (JPA의 근본적인 문제)

2022. 1. 4. 19:00[ 백엔드 개발 ]/[ Spring ]

양방향 연관관계

- 일반적으로 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이 클수록 병목지점이 될 수 있다.