[JPA] @OneToOne에서 Fetch 전략을 Lazy로 설정했을때 발생하는 이슈

Lazy Loading

JPA의 유일한 단점은 사용하기 쉬운만큼 성능적인 측면에서 발생할 수 있는 이슈를 간과하기 쉽다는 것인데, 성능이 안나올때 가장 먼저 고려해봐야할 부분이 즉시로딩(EAGER LOADING)으로 설정된 Fetch 전략이 있는지 확인하는 것이다.

하지만 @OneToOne 매핑시 Fetch 전략을 Lazy로 설정해도 EAGER로 동작하는 경우가 있다. 어떤 경우에 이러한 문제점이 발생하는지, 해결책은 무엇인지 예시를 통해 알아보도록 하자

예시 1. @OneToOne 단방향 매핑

@Entity
public class User {
    @Id
    @GeneratedValue
    @Column(name = "USER_ID")
    private Long id;

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "CART_ID")
    private Cart cart;

}
@Entity
public class Cart {
    @Id
    @GeneratedValue
    private Long id;
}

해당 예제는 일대일 단방향 매핑으로 외래키를 가지고 있는 USER가 연관관계의 주인이다.

다음과 같이 USER를 조회해보자.

userRepository.findByEmail(email).orElseThrow();

실행된 쿼리

select
    user0_.user_id as user_id2_9_,
    user0_1_.created_date as created_3_9_,
    user0_1_.modified_date as modified4_9_,
from
    user user0_
where
    user0_1_.email=?

실행된 쿼리를 보면 Lazy Loadging이 정상적으로 동작한다는 것을 알 수 있다.

예시 2. @OneToOne 양방향 매핑

@Entity
public class User {
    @Id
    @GeneratedValue
    @Column(name = "USER_ID")
    private Long id;

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "CART_ID")
    private Cart cart;

}
@Entity
public class Cart {

    @Id
    @GeneratedValue
    @Column("CART_ID")
    private Long id;

    @OneToOne(mappedBy = "cart", fetch = FetchType.LAZY)
    private User user;
}

해당 예제는 User와 Cart가 일대일 양방향 관계를 맺고 있고, 예시1과 동일하게 연관관계의 주인은 외래키를 가지고있는 USER다. 여기서도 아래와 같이 USER를 조회하면 정상적으로 Lazy Loading이 동작한다.

userRepository.findByEmail(email).orElseThrow();

하지만 문제는 Cart를 조회할때 발생한다. 다음과 같이 Cart를 조회해보자.

cartRepository.findById(id).get();