-
@OneToOne에서 발생하는 즉시로딩 문제Spring(Web) 2024. 5. 2. 16:42
문제 상황
현재 A Entity가 @OneToOne으로 두 개의 Entity를(C, D)를 갖고 있다. 연관관계의 주인이 아니기 때문에, mappedBy로 가지고 있는 상태이다. 이후 필터링 기반 동적조회 쿼리를 queryDSL로 작성했다. A Entity에서 @OneToOne 연관관계를 가진 Entity에 FetchType.LAZY를 적용해놓아도, C/D Entity가 계속해서 즉시로딩되며 문제를 발생시켰다.
100개의 A Entity row 조회였지만, respnose 시간이 2.18초로 매우 낮은 성능을 보여주었다...(평균적으로 2.5초 정도 걸렸다.)
원인
먼저 결과부터 말하면, JPA @OneToOne 연관관계에서 mappedBy로 Entity를 가지고 있는 Child Entity는, 항상 Parent Entity를 즉시로딩한다.
JPA는 FetchType.LAZY가 적용된 Entity를 지연로딩하기 위해 해당 Entity를 갖고 있는것이 아닌, 실제 Entity Class를 상속 받는 프록시 객체 형태로 만들어 둔다. 이 프록시 객체는 해당 Entity에 대한 참조만 가지고 있다. 하지만 mappedBy로 연결된 Entity에 대해서는 테이블에서 실제 ID를 갖고있지 않기 때문에, 프록시 객체를 만들기 위해 로딩을 해야만 한다.해결 방법
현재 양방향 매핑되어있는 @OneToOne을 끊거나, fetchJoin을 사용하는 방법등이 있다.
현재 개발중인 프로젝트에서 A Entity가 B/C Entity를 조회하는 경우는 없고, B/C Entity를 조회할 때 A Entity의 ID를 써서 조회하고 있으므로, 연결관계를 끊는 것으로 해결했다.
추가적으로 앞서 말했듯 fetchJoin을 사용해 해결할 수도 있다. 또한, 갖고있는 B/C Entity가 null이 아니라는것을 보장해주어도@OneToOneoptional = false) 해결할 수 있다.추가적인 의문점
@OneToOne에서 LAZY 로딩을 할 수 없는건, 해당 Entity에 직접적으로 Parent Entity의 id를 갖고있지 않기 때문에 할 수 없다고 했다. 그러면 @OneToMany 연관관계에서는 어떻게 LAZY 로딩을 적용하고 있는걸까?
쉽게 말하면 OneToOne 관계에서는 해당 Entity가 할당이 되지 않은 상태이면 애초에 null이기 때문에 Proxy 객체를 만들 수 없지만, OneToMany는 애초에 ArrayList 객체를 초기화하고 시작하기 때문에(size가 0인 List) 프록시 객체를 생성할 수 있게 된다. 따라서 Lazy 로딩을 위한 프록시 객체를 생성할 수 있게 된다.https://stackoverflow.com/questions/1444227/how-can-i-make-a-jpa-onetoone-relation-lazy
결론
결국, OneToOne 연관관계를 굳이 양방향 매핑을 해야될 이유가 없어서, 연관관계를 끊고 문제를 해결했다.
'Spring(Web)' 카테고리의 다른 글
검색 조건이 담긴 Body를 쓰는 HTTP 요청 METHOD는 GET일까 POST일까? (0) 2024.04.27 Pairing 기술블로그 (0) 2024.04.08 FetchType.EAGER, FetchType.LAZY (0) 2024.03.20 Spring Controller의 Stateless (0) 2022.07.07 Spring 핵심 원리 3 - 싱글톤 패턴과 스프링 컨테이너 (0) 2022.06.24