OneToOne 양방향 관계 조회 시 문제
Member
와 TitleName
, Member
와 Diligence
는 모두 OneToOne 양방향 관계로 구성이 되어 있으며,
연관관계의 주인은 Member
가 아닌 TitleName
과 Diligence
로 설정되어 있었다.
이렇다보니 문제가 하나 발생했는데.. 연관관계의 주인이 아닌 Member
를 조회할 때 Member
뿐만 아니라 TitleName
과 Diligence
까지 모두 조회되는 문제가 발생했다.
왜 이런 문제가 발생하는걸까?
지연 로딩 동작 매커니즘
지연 로딩이 동작하는 매커니즘은 다음과 같다.
- 지연 로딩은 로딩되는 시점에 Fetch 전략이 Lazy로 설정되어있는 엔티티를 프록시 객체로 가져온다.
- 이후 실제로 객체를 사용하는 시점에 초기화되면서 쿼리가 실행된다.
이렇게 지연 로딩으로 설정이 되어있는 엔티티를 조회할 때는 프록시로 감싸서 동작하게 되는데, 프록시는 null
을 감쌀 수 없기 때문에 이와 같은 문제점이 발생하게 된다.
즉, 프록시의 한계로 인해 발생하는 문제이다.
연관관계의 주인이 아닌 Member
를 조회할 때, Member
는 Diligence
, TitleName
을 참조할 수 있는 컬럼을 갖고 있지 않으므로 Member
는 어떤 Diligence
, TitleName
에 의해 참조되고 있는지 알 수 없다.
즉, Diligence
나 TitleName
이 null
이더라도 Member
는 이를 알 수 있는 방법이 없다. 반대로 null
이 아닌지도 확인이 불가능하다.
=> Member
조회 시 Diligence
, TitleName
의 존재여부를 확인할 수 없기에, 그 존재 여부를 확인하는 쿼리가 발생하게 된다.
해결 방법
근본적으로 이 문제를 해결할 수 있는 방법은 따로 없다.. 다음 3가지 중 하나를 선택하여 회피하는 전략을 취한다.
- 구조 변경
- 양방향 매핑 필요 여부 다시 확인 후, 필요하지 않다면 삭제
- OneToOne -> OneToMany 또는 ManyToOne 관계로 변경이 가능한지 생각
- 구조 유지한채 해결
Member
를 조회할 때,Diligence
,TitleName
도 함께 조인(Fetch Join or Entity Graph)- batch fetch size 사용
- 연관관계 주인 변경
- 연관관계 주인을 모두
Member
로 옮긴다.(Diligence
,TitleName
만 따로 조회할 때는 같은 문제 발생)
- 연관관계 주인을 모두
=> 우리 서비스의 경우, Diligence
나 TitleName
만 따로 조회하는 경우는 거의 없으며 Member
를 더 자주 조회하므로 연관관계의 주인을 Member
로 변경하기로 했다.
결론
- OneToOne 양방향 매핑에서 연관관계의 주인이 아닌 쪽에서 조회하게 되면 프록시 객체를 생성할 수 없기 때문에 지연 로딩으로 설정해도 즉시 로딩으로 동작
- 프록시는
null
을 감쌀 수 없기 때문에 참조하고 있는 객체가null
인지null
이 아닌지 확인하는 쿼리를 실행해야 하기 때문
'Project' 카테고리의 다른 글
[TODOMON] EP.15 로그관리 with ELK (0) | 2025.02.07 |
---|---|
[TODOMON] EP.14 중복 쿼리 제거하기 with OSIV, AOP, JWT (0) | 2025.02.07 |
[TODOMON] EP.12 아무것도 모르는 나의 동시성 문제 해결기 (0) | 2025.02.05 |
[TODOMON] EP.11 인덱스를 통한 투두 조회 API 성능 개선 feat. 인덱스 컨디션 푸시다운 (0) | 2025.02.04 |
[TODOMON] EP.10 캐싱을 통한 전체 & 소셜 랭킹 조회 API 개선하기 w/ Redis (1) | 2025.02.04 |