본문 바로가기
Spring/JPA

[JPA] OSIV (Open Session In View)를 사용하여 JPA 성능 최적화

by 코딩균 2022. 3. 11.

JPA에서의 Entity manager == Hibernate에서의 Session

즉, 사실상 JPA에서는 Open Entity Manager In View라고 생각하면 된다

 

JPA가 언제 DB Connection을 얻는가?

DB Transaction을 시작할 때 JPA persistence context가 connection 가져온다

 

JPA가 언제 DB Connection을 돌려주는가?

open-session-in-view가 켜져있는 경우

Service @Transactional 걸린 메소드를 벗어나도, client에게 값이 반환될 때까지 돌려주지 않는다

  • view template의 경우 html과 data 모두 랜더링 후
  • API의 경우 json으로 값이 client에게 tansfer된 후

지연 로딩 때문에 영속성 컨텍스트가 살아서 data를 가지고 올 수 있어야 한다

모든 작업이 끝난 후 connection 돌려주기 -> 영속성 컨텍스트 사라짐

 

open-session-in-view가 꺼져있는 경우

Sevice단에서 @Transactional 이 걸린 transaction이 끝나면 

Controller 단으로 data 반환한 시점부터는 

connection 돌려주고 영속성 컨텍스트 반환한다

 

Open-Session-In-View 의 단점

open-session-in-view ON 경우

오랜 시간 동안 connection을 가지고 있어서,

실시간 처리 application에서는 트래픽이 과부하걸릴 수 있다.

예시)

외부 API 연결하는데 외부 API 처리시간이 오래 걸린다면 내가 만든 Application도 해당 외부 API와의 DB connection 해제 못하고 다른 task들을 처리하지 못한다 ->  Thread pool이 오버플로우 될 때까지 대기 또 대기..

 

open-session-in-view OFF 경우

connection 뿐만 아니라 영속성 컨텍스트도 반환되기 때문에

모든 지연로딩은 service - repository 단 즉, transaction 안에서 끝내버려야 함

-> controller와 view 단에서 지연로딩하면 안된다 즉, 철저하게 계층 분리 필요

 

 

설정하는 방법

application.yml

spring:
	jpa:
    	open-in-view : true / false

 

 

OFF 인 상태에서 그럼 어떻게해..?

false 한 후에 transaction 외부에서 지연로딩을 한 경우

could no initialize proxy - no Session (LazyInitializeException) 이라는 에러를 만나게 된다

즉, session = db connection이 없어져서 proxy 객체에 접근했을 때, data를 가져올 수가 없다는 것이다

  1. fetch join 을 해서 proxy를 실제 entity로 채우거나 (사실상 지연로딩이 아님)
  2. transaction 안에서 지연로딩을 이미 다 끝내거나

따라서 open-in-view 가 false인 경우 위의 두가지 방법으로 controller 단에 가기 전에 미리 불러와야 한다

 

유지보수의 효용성을 위해 아래와 같이 service 단을 나누기도 함 (회사 레거시에 따라 다를 수 있음)

  • 화면에 맞춘 Service - life cycle 빠름 (요구사항 변화에 따라 자주 변함)
  • 핵심 비즈니스 로직에 맞춘 Service - life cycle 느림 (잘 변할 일이 없음)

 

 

서비스 특징에 따른 OSIV on/off

  • 고객 서비스 기반 - api 트래픽이 많은 경우에는 off
  • 회사 내부 서비스 기반 - admin 등 트래픽이 적은 경우 on