Lazy Loading과 LazyInitializationException 그리고 OSIV란?

coldrice99·5일 전
0
post-thumbnail

1. Lazy Loading의 개념

  • Lazy Loading은 실제로 필요한 시점까지 데이터를 "지연"하여 조회하는 방식으로, 데이터베이스와 연결된 Entity 객체들을 필요할 때만 가져와 성능을 최적화하려는 기법입니다.

  • 예를 들어, CommentTodo와 관계가 있는 상황에서 FetchType.LAZY를 설정하면 Comment 객체를 조회할 때 Todo는 즉시 불러오지 않습니다. Todo가 실제로 필요해지는 시점에 비로소 데이터베이스에서 쿼리를 실행하게 됩니다.

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "todo_id")
    private Todo todo;
  • 이 설정을 통해 Comment를 조회하더라도 Todo는 필요해질 때까지 조회하지 않게 되므로, 불필요한 데이터베이스 호출을 줄일 수 있습니다.

2. Lazy Loading의 작동 방식 (Proxy 객체)

  • Proxy 객체가 Lazy Loading의 핵심입니다. Comment를 조회할 때 Todo는 즉시 사용되지 않기 때문에, Todo 자리에는 대신 Proxy 객체가 들어갑니다.

  • Proxy 객체는 진짜 데이터가 필요해지는 순간 데이터베이스에서 데이터를 조회하여 가져옵니다.

    예를 들어, Comment를 조회한 후 Todotitle을 참조하게 되면 그때서야 Todo의 데이터가 데이터베이스에서 조회됩니다.

3. LazyInitializationException: Lazy Loading 실패 시 발생하는 에러

LazyInitializationException은 Lazy Loading을 사용할 때 세션(Session)이 없을 때 발생하는 오류입니다.

  • 세션이 없다는 것은, Entity가 데이터베이스와 연결된 상태가 아니라는 것을 의미합니다.
  • Spring에서는 보통 트랜잭션이 종료될 때 Entity가 "영속성 컨텍스트"를 벗어나기 때문에 이 에러가 자주 발생합니다.

예시: LazyInitializationException이 발생하는 상황

public CommentResponse retrieveCommentById(Long commentId) {
    Comment comment = commentService.retrieve(commentId);
    return CommentResponse.from(comment); // 여기서 Lazy Loading 발생!
}

위 코드에서 commentService.retrieve()가 트랜잭션 범위를 벗어나면, 영속성 컨텍스트도 사라져서 Comment와 연결된 Todo의 데이터에 접근할 때 LazyInitializationException이 발생할 수 있습니다.

4. LazyInitializationException 해결 방법

방법 1: 트랜잭션 내부에서 Lazy Loading 발생

  • Lazy Loading이 필요한 시점이 트랜잭션 내부로 유지되도록 코드를 수정하는 것입니다.
  • 예를 들어, CommentService에서 필요한 데이터를 미리 조회하여 반환하도록 리팩토링하는 방식입니다.

방법 2: OSIV (Open Session In View)

  • OSIV (Open Session In View)는 데이터베이스와의 연결(Session)을 Controller(View 단계)까지 유지하는 방식입니다.
  • 기본적으로 OSIV가 활성화되어 있어, View 단계에서 Lazy Loading이 발생하더라도 세션이 열려 있어 LazyInitializationException이 발생하지 않습니다.

그러나 OSIV는 추천되지 않습니다.

  1. DB 연결 과다 점유: 세션을 오랫동안 열어두면 데이터베이스 리소스가 불필요하게 점유될 수 있습니다.
  2. 설계상의 문제: 영속성 컨텍스트가 Controller까지 열려 있으면, Entity가 너무 많은 계층에 관여하게 되어 유지보수에 불리할 수 있습니다.
spring:
  jpa:
    open-in-view: false  # OSIV 비활성화 설정

결론: Lazy Loading, LazyInitializationException, OSIV까지 살펴본 결과, 무작정 옵션을 켜두기보다는 필요한 시점에 트랜잭션 내에서 적절하게 데이터를 조회하도록 하는 것이 중요하다는 점을 확인할 수 있었습니다. 📝

profile
서두르지 않으나 쉬지 않고

0개의 댓글