0. 개요
- 지금까지 JPA 기본 개념에 대해서 알아보았다.
- 이번 포스팅은 JPA의 마지막 개념인 OSIV에 대해서 알아보자.
1. OSIV(Open Session In View)
a) OSIV 란?
- Open Session In View란, 하이버네이트 또는 JPA를 지칭하는 이름이다.
- JPA는 Open Entity Manager In View이라 불리기도 하는데, 관례상 OSIV로 통일하여 부른다.
b) OSIV 사용 설정
- JPA를 사용하면 Spring에서 기본적으로 spring.jpa.open-in-view의 옵션 값을 TRUE로 설정한다.
- 이는 OSIV 옵션을 사용한다는 의미로, JPA 프로젝트 빌드 시점에 다음과 같은 warn 로그에서 확인할 수 있다.
c) OSIV의 기능
- OSIV는 영속성 Context의 라이프 사이클 범위(= Scope)를 설정하는 옵션이다.
- 즉, 언제까지 영속성 Context를 살려둘 것이냐에 대한 설정 옵션이다.
2. OSIV와 영속성 Context
a) 영속성 Context의 유효성
- 영속성 Context는 DB Connection과 동일한 라이프 사이클을 갖는다.
→ DB Connection의 시작과 함께 영속성 Context가 유효하다.
→ DB Connection의 종료와 함께 영속성 Context는 사라진다.
b) OSIV의 역할 - 영속성 Context의 유효함
- OSIV 옵션을 사용하면 영속성 Context의 유효성이 다음 그림과 같은 범위를 갖는다.
- OSIV는 request가 들어온 시점부터 response가 나가는 시점까지 영속성 Context를 살려놓는다.
- 앞서 영속성 Context는 DB Connection과 동일한 라이프사이클을 갖는다고 설명하였다.
- 즉, 영속성 Context가 살아있다면 DB Connection 또한 함께 살아있는 것이다.
c) OSIV의 역할 - Lazy Loading
- Lazy Loading이 어떻게 작동하는지 생각해보자.
- Entity Manager를 통해 객체를 조회한다.
- 조회된 객체 내부에 Lazy Loading이 걸린 필드는 최초 조회 시점에서 proxy 값을 할당받는다.
- 해당 필드의 값이 요청되면 Lazy Loading이 발현되고, 해당 필드의 값을 DB로부터 조회한다.
- 즉, Lazy Loading이 가능하려면 DB Connection이 계속 살아있어야 하는 것이다.
- 결론적으로, 이것이 OSIV의 장점이자 Lazy Loading이 가능한 이유다.
3. OSIV 사용의 문제점
a) DB Connection의 부족
- OSIV는 request부터 response까지 영속성 Context를 살려놓기 위해 DB Connection을 유지한다.
- 예를 들어, API 호출 시점부터 API 요청이 처리되어 데이터가 반환되는 시점까지 DB Connection이 유지되는 것이다.
- 그러므로 실시간 트래픽이 중요한 애플리케이션에게는 DB Connection 리소스가 부족할 수 있다.
- 동시 다발적인 request로 인해 request를 처리하는 Thread Pool이 모두 소모될 수 있기 때문이다.
4. OSIV를 사용하지 않는다면
a) OSIV를 사용하지 않는 경우
- 다음 그림은 OSIV를 사용하지 않을 때의 영속성 Context의 유효 범위다.
- 위의 그림처럼 DB Connection의 종료 시점에서 영속성 Context는 유효하지 않게 된다.
b) OSIV 비사용의 장단점
- OSIV를 사용하지 않으면 Lazy Loading을 사용하지 못한다. 더 이상 DB Connection이 유효하지 않기 때문이다. (단점)
즉, 모든 지연 로딩 처리를 DB Transaction 내부에서 처리해야 한다.(DB Connection 종료 전에 강제 호출 필요함)
- 다만 실시간 트래픽이 중요한 애플리케이션의 경우, Connection 리소스의 회전율을 높일 수 있는 전략이다. (장점)
5. OSIV 없이 Lazy Loading 사용 전략
- OSIV를 사용하지 않는다는 것은 영속성 Context의 유효 범위가 작다는 것을 의미한다.
- 즉, 영속성 Context가 유효한 시점을 고려하여 애플리케이션을 설계하면 되는 것이다.
a) 커맨드와 쿼리의 분리
- 가장 대표적인 방법으로 커맨드와 쿼리를 분리하는 방법이 있다.
- 이는 핵심 비즈니스를 담당하는 쿼리(= 커맨드)와 그 외의 쿼리를 분리하여 관리하는 방법이다.
- 비즈니스 로직은 Entity를 등록하거나 특정 Entity를 수정하는 작업을 수행하기에 성능 문제가 발생하지 않는다.
- 그러나 화면을 출력하는 조회 Service에서 복잡한 쿼리를 필요로 하여 성능 문제가 발생한다.
- 즉, 비즈니스 로직의 쿼리와 화면을 출력하는 조회 쿼리를 분리하여 관리하는 것이다.
- 예를 들면 다음과 같이 분리할 수 있다.
→ OrderService: 주문 Entity를 관리하는 핵심 쿼리가 담긴 서비스
→ OrderQueryService: 주문 Entity를 조회하는 쿼리를 관리하는 서비스
b) 결론
- OSIV를 항상 끄거나 켜놓기보다는 필요에 의해서 모듈에 따라 목적에 맞게 OSIV를 사용하는 것을 권장한다.
ex) 고객 서비스에서는 OSIV를 꺼놓는다. (실시간 트래픽이 중요, 읽기 전용 조회 서비스를 따로 만든다)
ex) Admin 서비스에서는 OSIV를 켜놓는다. (실시간 트래픽이 중요하지 않음)
'Back-end > JPA 개념' 카테고리의 다른 글
Query DSL이란? (0) | 2022.06.08 |
---|---|
Spring Data JPA란? (0) | 2022.06.07 |
API 조회 성능 최적화 - 컬렉션(DTO 직접 조회) (0) | 2022.06.04 |
API 조회 성능 최적화 - 컬렉션(Fetch Join + 페이징 + Batch Size) (0) | 2022.06.03 |
API 조회 성능 최적화 - 컬렉션(Fetch Join, distinct) (0) | 2022.06.02 |
댓글