OSIV
OSIV : Open Session In View
spring.jpa.open-in-view
- JPA EntityManager를 request의 전체 처리 과정동안 thread에 binding한다.
- request의 life cycle동안 lazy loading을 사용할 수 있게한다.
org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor
- spring web request interceptor
org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter
- servlet filter
osiv 옵션을 켜게 되면 위의 filter / interceptor에서 request가 오는 시점에 해당 thread에 entity manger를 매핑한다.
그리고 response가 나가는 시점에 해당 filter / interceptor에서 entity manager를 종료한다.
request의 전체 life cycle동안 lazy loading을 자유롭게 사용할 수 있는 장점이 있지만, database connection을 계속 들고 있다는 문제점이 있다.
사용자의 트래픽이 몰리거나 API 호출 과정에서 외부 API 호출과 같이 오버헤드가 큰 API라면 database connection이 부족해지는 상황이 발생할 수 있고, 이는 곧 장애로 이어질 수 있다.
OSIV 옵션을 끄게 되면 transaction 생성 ~ 종료 시점에만 entity manager를 가지고 있게 된다.
즉, 꼭 필요한 부분에서만 database connection을 사용하게 하는 것이다.
하지만 이때 transaction 밖에서 lazy loading을 사용하려고 하면 LazyInitializationException
이 발생하게 된다.
이 문제를 해결하기 위해서는 transaction 안에서 entity들을 모두 초기화 시켜 놓아야 한다.
fetch join
, @EntityGraph
, Hibernate.initialize()
와 같은 방법으로 위의 문제를 회피할 수 있다.
정리
각 기술은 trade-off가 있다.
OSIV 옵션을 사용하면 Lazy Loading의 자유로운 사용으로 개발 생산성을 향상시킬 수 있지만, 예상치 못한 곳에서 N + 1 문제를 마주할 수 있고, database connection 부족으로 장애가 발생할 수 있다는 문제가 있다.
OSIV 옵션을 사용하지 않으면, transaction안에서 모든 연관관계의 객체를 초기화시켜야 한다는 불편함이 있지만 꼭 필요한 곳에서만 database connection을 사용하고 반환하여 더 많은 사용자가 application을 이용할 수 있게 한다.