OEIV : OpenEntityManagerInView

OEIV

OpenEntityManagerInView (OEIV)는 Spring Framework와 JPA(Java Persistence API)를 함께 사용할 때 발생하는 지연 로딩(Lazy Loading) 문제를 웹 환경에서 해결하기 위해 설계된 패턴이자 Spring에서 제공하는 인터셉터(Interceptor)


1.  OEIV의 개념 및 목적

목적웹 요청 처리 과정 전체에서 JPA의 EntityManager를 열린 상태로 유지하여, View 렌더링 단계에서 발생하는 지연 로딩 예외(Lazy Loading Exception)를 방지
작동 방식Spring의 DispatcherServlet이 HTTP 요청을 받으면, OpenEntityManagerInViewInterceptor가 트랜잭션과 관계없이 EntityManager를 생성하고 쓰레드 로컬(ThreadLocal)에 바인딩
종료 시점HTTP 응답을 보내기 직전에 EntityManager를 닫고 쓰레드 로컬에서 제거

지연 로딩(Lazy Loading) 문제 (N+1 문제와 구별)

일반적으로 JPA는 트랜잭션 경계 내에서만 엔티티의 연관 관계를 로딩(지연 로딩)할 수 있음.

1. Service 계층: EntityManager를 사용하여 데이터를 조회하고 트랜잭션을 종료합니다. (이때 엔티티는 영속성 컨텍스트에서 분리된 상태가 됨)
2. Controller & View 계층: View를 렌더링하는 과정에서 분리된 엔티티의 @ManyToOne이나 @OneToMany 관계 필드를 접근하려고 시도
3. 오류 발생: EntityManager가 이미 닫혔기 때문에, 데이터베이스 접근이 불가능하여 LazyInitializationException이 발생합니다.

OEIV는 이 전체 웹 요청 주기 동안 EntityManager를 열어둠으로써 View 계층에서도 자유롭게 지연 로딩을 수행.

OEIV의 주된 목적은 View 렌더링 과정에서 발생하는 문제를 해결하는 것
* View는 HTML 응답을 만들기 위해 모델 객체의 데이터를 읽어 화면을 꾸미는 단계 전체를 의미

OEIV 미적용 (LazyInitializationException 발생)

“데이터를 가져오려는데 문이 닫혔어요!” (LazyInitializationException)

JPA(Hibernate)를 사용할 때 성능을 위해 연관된 데이터를 바로 가져오지 않고, 실제로 필요할 때 가져오는 지연 로딩(Lazy Loading) 전략을 자주 사용. (예: User 정보를 가져올 때, 그 유저의 Order(주문 목록)는 당장 필요 없으니 나중에 가져오기로 설정).

하지만 기본적으로 데이터베이스 세션(영속성 컨텍스트)은 서비스 계층의 트랜잭션이 끝날 때 함께 닫

문제는 컨트롤러가 뷰(HTML 템플릿이나 JSON 직렬화)에 데이터를 넘겨준 후, 뷰가 화면을 그리는 도중에 지연 로딩된 데이터(예: 주문 목록)를 요청할 때 발생. 이때는 이미 데이터베이스 세션의 문이 닫힌 상태라 데이터를 가져올 수 없어 에러가 발생

Service가 끝나는 순간 DB 세션(영속성 컨텍스트)도 같이 죽는다는 점

OEIV 적용

“뷰(View)가 화면을 다 그릴 때까지 데이터베이스 세션(EntityManager)의 문을 열어두자!”

OEIV 패턴을 적용하면 (보통 필터나 인터셉터를 통해 구현), HTTP 요청이 웹 애플리케이션에 들어오는 순간 데이터베이스 세션을 열고, 그리고 컨트롤러, 서비스를 거쳐 뷰가 완전히 렌더링 되고 응답이 나갈 때까지 세션을 닫지 않고 유지

덕분에 뷰 계층에서 지연 로딩된 데이터가 필요해지더라도, 아직 세션이 열려있기 때문에 문제없이 데이터베이스에 추가 쿼리를 날려 데이터를 가져올 수 있음.

Filter 레벨에서 DB 세션을 미리 열고, View 렌더링이 끝날 때까지 닫지 않는 것


2.  Spring Boot에서의 설정 및 제어

Spring Boot는 OEIV를 자동으로 설정

spring.jpa.open-in-viewtrueSpring Boot 2.x 기준 기본값 -> OEIV 인터셉터를 활성화

설정 방법

application.properties 또는 application.yml 설정

spring.jpa.open-in-view=true(기본값) OEIV가 활성화됩니다. View에서 지연 로딩이 가능
spring.jpa.open-in-view=falseOEIV가 비활성화. 지연 로딩은 트랜잭션 경계 내에서만 가능하며, View에서 지연 로딩을 시도시 LazyInitializationException이 발생

3. OEIV의 단점 및 주의사항

트래픽 부하 및 성능 저하HTTP 요청이 끝날 때까지 데이터베이스 연결 세션(Connection)을 붙잡고 있게 되어, 동시 접속자 수가 늘어날 경우 DB Connection Pool의 고갈을 유발 가능
트랜잭션 오염서비스 계층의 트랜잭션이 종료된 후에도 View 렌더링 과정에서 예상치 못한 지연 로딩으로 추가적인 쿼리가 발생할 가능 (이른바 N+1 문제 심화)

“OEIV : OpenEntityManagerInView”에 대한 1개의 생각

댓글 남기기