개발/Java & Kotlin

[JPA] JPA에서 양방향 @OneToOne 관계와 Lazy Loading의 한계

devhooney 2025. 4. 6. 17:19
728x90


JPA에서 @OneToOne 양방향 관계를 사용할 때, 연관 관계의 주인이 아닌 엔티티를 조회하는 경우 Lazy Loading이 제대로 동작하지 않는 이유와 그 해결책에 대해 살펴보자.

 

 

728x90

 

1. Lazy Loading의 동작 원리
Lazy Loading은 엔티티를 실제로 사용할 때 데이터베이스에서 해당 연관된 데이터를 조회하는 전략이다. 이때 JPA는 연관된 엔티티가 실제로 필요할 때만 쿼리를 실행하여 데이터를 가져오는데, 이를 통해 성능을 최적화할 수 있다.

@Entity
public class User {
    @OneToOne(fetch = FetchType.LAZY)
    private Profile profile;
}

@Entity
public class Profile {
    @OneToOne(mappedBy = "profile", fetch = FetchType.LAZY)
    private User user;
}

 

위와 같은 양방향 @OneToOne 관계에서 User 엔티티를 조회하면, Profile은 Lazy 방식으로 로딩될 것으로 예상된다.

 

 

 

 

2. 연관관계의 주인이 아닌 엔티티에서 Lazy Loading이 동작하지 않는 이유
하지만, 양방향 관계에서 연관 관계의 주인이 아닌 엔티티를 조회할 경우, Lazy Loading이 제대로 동작하지 않는다. 그 이유는 JPA가 연관된 엔티티의 존재 여부를 확인하기 위해 추가적인 쿼리를 실행하는데, 이때 연관 관계의 주인이 아닌 쪽은 해당 연관 관계를 참조할 외래 키(FK)가 없기 때문에 연관 관계의 존재 여부를 알지 못한다.

따라서 JPA는 Lazy Loading을 사용하더라도, 연관된 엔티티의 존재 여부를 확인하기 위해 추가적인 쿼리를 실행하게 되고, 이로 인해 Lazy Loading이 동작하지 않는 것이다.

 

 

 

 

3. 해결책: 단방향 모델링
이 문제를 해결하는 가장 간단한 방법은 연관 관계를 단방향으로 모델링하는 것이다. 양방향 관계가 필요 없다면, 연관 관계의 주인만 설정하여 문제를 방지할 수 있다.

@Entity
public class User {
    @OneToOne(fetch = FetchType.LAZY)
    private Profile profile;
}

이렇게 단방향으로 설정하면 User 엔티티에서 Profile을 조회할 때 Lazy Loading이 정상적으로 동작한다.

 

 

 

 

4. 해결책: @EntityGraph 사용
또 다른 해결책으로는 @EntityGraph를 사용하여 연관된 엔티티를 즉시 로딩(Eager Loading)할 수 있다. @EntityGraph는 연관된 엔티티를 함께 조회할 때 유용하게 사용할 수 있다.

@EntityGraph(attributePaths = "profile")
public User findUserWithProfile(Long id);

이렇게 하면 Lazy Loading 대신, 해당 엔티티와 연관된 Profile을 즉시 로딩할 수 있다.

 

 

 

5. 결론
양방향 @OneToOne 관계에서 연관 관계의 주인이 아닌 엔티티를 조회할 때 Lazy Loading이 동작하지 않는 문제는 JPA의 한계다. 이를 해결하기 위해서는 단방향으로 모델링하거나, 즉시 로딩이나 @EntityGraph를 활용하는 방법을 고려해볼 수 있다. 성능 최적화와 설계의 복잡도를 잘 고려하여 Lazy Loading이 정말 필요한지 다시 한번 검토해보는 것이 중요하다.

 

 

 

끝!

 

728x90