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-view | true | Spring Boot 2.x 기준 기본값 -> OEIV 인터셉터를 활성화 |
설정 방법
application.properties 또는 application.yml 설정
| spring.jpa.open-in-view=true | (기본값) OEIV가 활성화됩니다. View에서 지연 로딩이 가능 |
| spring.jpa.open-in-view=false | OEIV가 비활성화. 지연 로딩은 트랜잭션 경계 내에서만 가능하며, View에서 지연 로딩을 시도시 LazyInitializationException이 발생 |
3. OEIV의 단점 및 주의사항
| 트래픽 부하 및 성능 저하 | HTTP 요청이 끝날 때까지 데이터베이스 연결 세션(Connection)을 붙잡고 있게 되어, 동시 접속자 수가 늘어날 경우 DB Connection Pool의 고갈을 유발 가능 |
| 트랜잭션 오염 | 서비스 계층의 트랜잭션이 종료된 후에도 View 렌더링 과정에서 예상치 못한 지연 로딩으로 추가적인 쿼리가 발생할 가능 (이른바 N+1 문제 심화) |
“OEIV : OpenEntityManagerInView”에 대한 1개의 생각