본문 바로가기
Development

[ORM] OSIV 옵션이 무엇인가요

by 한휴르 2025. 1. 20.

OSIV(Open Session In View)

OSIV(Open Session In View) 는 JPA / Hibernate 등 ORM(Object Relation Mapping) 기술을 사용하는 환경에서, 하나의 영속성 컨텍스트(또는 세션)를 뷰 렌더링(화면 처리)까지 열어두는 것을 말합니다. 영속성 컨텍스트가 살아있으면 엔티티는 영속 상태로 유지될 수 있어서 뷰에서도 지연 로딩(Lazy Loading)을 사용할 수 있습니다. 즉, 뷰에서도 지연 로딩이 가능하도록 하기위해 사용하는 것이 OSIV입니다.

왜 OSIV가 필요한가요?

ORM 기술에서 지연 로딩 기능을 사용할 때, 실제로 엔티티가 관계를 통해 참조하고 있는 데이터(OneToMany, ManyToOne 같은)를 즉시 불러오지 않고 필요할 때까지 로딩을 미루는 경우가 많습니다.
문제는 웹 애플리케이션에서도 일반적으로 "서비스 계층(비즈니스 로직) -> 트랜잭션 종료 -> 뷰 렌더링" 순으로 작업이 진행되는데, 지연 로딩이 필요한 시점(뷰 렌더링)이 이미 트랜잭션이 종료되어 영속성 컨텍스트가 닫힌 다음일 수 있습니다.

트랜잭션이 끝나면 영속성 컨텍스트가 닫히고, 엔티티를 통해 지연 로딩을 시도하면 LazyInitializationException이 발생하게 됩니다.

이런 상황에서 OSIV를 활성화하면 HTTP 요청이 시작될 때 영속성 컨텍스트(세션)을 열고, 뷰 렌더링이 끝날 때까지(응답을 보내기 직전) 닫지 않습니다. 즉, 컨트롤러나 뷰 단계에서도 지연 로딩을 수행할 수 있도록 보장해주는 방식입니다.

OSIV 동작 원리

OSIV의 동작 방식에 대해서 Spring Framework가 제공하는 OSIV을 통해 알아보겠습니다. 스프링이 제공하는 OSIV 클래스는 서블릿 필터에서 적용할지 스프링 인터셉터에서 적용할지에 따라 원하는 클래스를 선택해서 사용하면 됩니다.

  • JPA OEIV 서블릿 필터: org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter
  • JPA OEIV 스프링 인터셉터: org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor

Spring OSIV는 OSIV를 사용하면서 트랜잭션은 비즈니스 계층에서만 사용합니다. 영속성 컨텍스트는 사용자의 요청 시점에서 생성이 되지만, 데이터를 쓰거나 수정할 수 있는 트랜잭션은 비즈니스 계층에서만 사용할 수 있도록 트랜잭션이 일어납니다.

  • spring.jpa.open-in-view : true 기본값

Spring Boot JPA 의존성을 주입 받아 어플리케이션을 구성할 경우 spring.jpa.open-in-view의 기본값인 true로 지정되어 있어 OSIV가 적용된 상태로 어플리케이션이 구성됩니다.

동작 원리는 다음과 같습니다.

  1. 클라이언트의 요청이 들어오면 서블릿 필터나, 스프링 인터셉터에서 영속성 컨텍스트를 생성합니다. 단 이 시점에서 트랜잭션은 시작하지 않습니다.
  2. 서비스 계층에서 @Transeactional로 트랜잭션을 시작할 때 미리 생성해둔 영속성 컨텍스트를 찾아와서 트랜잭션을 시작합니다.
  3. 서비스 계층이 끝나면 트랜잭션을 커밋하고 영속성 컨텍스트를 플러시합니다. 이 시점에 트랜잭션은 끝내지만 영속성 컨텍스트는 종료되지 않습니다.
  4. 컨트롤러와 뷰까지 영속성 컨텍스트가 유지되므로 조회한 엔티티는 영속 상태를 유지합니다.
  5. 서블릿 필터나, 스프링 인터셉터로 요청이 돌아오면 영속성 컨텍스트를 종료합니다. 이때 플러시를 호출하지 않고 바로 종료합니다.

OSIV의 단점

이러한 OSIV의 문제점은 무엇일까요?

  • 표현 계층에서 엔티티를 수정할 경우 이를 데이터베이스에 반영하지 않습니다. 하지만, 엔티티를 수정한 이후 트랜잭션을 시작하는 응용 계층을 시작한 경우에 문제가 발생합니다. 응용 계층 트랜잭션이 끝나고 영속성 컨텍스트를 플러시하는 과정에서 변경 감지가 동작할 수 있습니다.
  • 뷰 단에서 무심코 다수의 엔티티 필드를 순회하면서 지연 로딩이 발생하면, 예상치 못한 대량의 쿼리가 실행될 수 있습니다(N+1 쿼리 이슈)
  • OSIV가 활성화되어 있으면, 데이터베이스 커넥션이 실제로 길게 점유되지는 않더라도 세션이 긴 범위(요청 전역)를 차지하게 됩니다. 대규모 트래픽 환경에서 OSIV 때문에 병목이 발생하거나 커넥션 풀 고갈 문제가 생길 수도 있습니다.
  • 비즈니스 로직 외부(특히 뷰)에서 마음대로 지연 로딩을 사용하는 것은 계층간 책임이 불분명해지는 결과를 초래할 수 있습니다.

정리

OSIV(Open Session In View)는 뷰 렌더링까지 영속성 컨텍스트를 열어 두어 지연 로딩이 가능하게 하는 옵션입니다. 사용하기는 편리하지만, 잘못 사용하면 성능 문제(N+1 쿼리), 계층 분리 모호화 등의 부작용이 생길 수 있으므로 주의 깊게 설정해야 합니다.

일반적으로 작은 규모의 애플리케이션이나 개발 편의를 우선하는 초기 단계에서는 OSIV를 활성화해도 문제가 없을 수 있습니다. 하지만 트래픽이 많아지고, 뷰에서 발생하는 N+1 문제를 해결해야 하거나, 비즈니스 로직과 뷰 로직을 확실히 분리하려면 OSIV를 끄고 필요한 데이터를 서비스 계층에서 명시적으로 로딩해 넘기는 것이 권장됩니다.

모든 기술이 그러하듯 상황에 맞춰서 적절하게 사용하는 것이 중요합니다.

댓글