OSIV (Open Session in View)

정종일·2023년 4월 22일
0

Spring

목록 보기
7/18

개념

OSIV는 영속성 컨텍스트를 View까지 열어두는 기능이다. 영속성 컨텍스트가 유지되면 엔티티도 영속 상태로 유지된다. View까지 영속성 컨텍스트가 살아있다면 View에서도 지연 로딩을 사용할 수 있다. 영속성 컨텍스트가 유지되기 때문에 View Template이나 API 컨트롤러에서 지연 로딩이 가능하다.

JPA에서는 Open EntityManager in View라고 부르지만 관례상 둘 다 OSIV로 부른다.

OSIV 동작 원리

적용 지점 선택

Spring Framework에서 제공하는 OSIV 클래스는 서블릿 필터에서 적용할지 인터셉터에서 적용할지에 따라 원하는 클래스를 선택해 사용한다.

영속성 컨텍스트는 사용자의 요청 시점에서 생성되지만, 데이터를 쓰거나 수정할 수 있는 트랜잭션은 비즈니스 계층에서만 사용할 수 있도록 트랜잭션이 일어난다.

• spring.jpa.open-in-view : true 기본값

동작 원리

  • 클라이언트의 요청이 들어오면 서블릿 필터나, 스프링 인터셉터에서 영속성 컨텍스트를 생성한다. 단 이 시점에서 트랜잭션은 시작하지 않는다.
  • 서비스 계층에서 @Transeactional로 트랜잭션을 시작할 때 1번에서 미리 생성해둔 영속성 컨텍스트를 찾아와서 트랜잭션을 시작한다.
  • 서비스 계층이 끝나면 트랜잭션을 커밋하고 영속성 컨텍스트를 플러시한다. 이 시점에 트랜잭션은 끝내지만 영속성 컨텍스트는 종료되지 않는다.
  • 컨트롤러와 뷰까지 영속성 컨텍스트가 유지되므로 조회한 엔티티는 영속 상태를 유지한다.
  • 서블릿 필터나, 스프링 인터셉터로 요청이 돌아오면 영속성 컨텍스트를 종료한다. 이때 플러시를 호출하지 않고 바로 종료한다.

특징

트랜잭션이 끝나면 컨트롤러와 뷰에는 트랜잭션이 유지되지 않는 상태이다. 엔티티를 변경하지 않고 단순히 조회만 할 때는 트랜잭션이 없어도 동작한다. 따라서 프록시를 뷰 렌더링하는 과정에 초기화가 일어나게 되어도 조회 기능이므로 트랜잭션 없이 읽기가 가능하다.

  • 영속성 컨텍스트는 기본적으로 트랜잭션 범위 안에서 엔티티를 조회하고 수정할 수 있다.
  • 영속성 컨텍스트는 트랜잭션 범위 밖에서 엔티티를 조회만 가능하다. (트랜잭션 없이 읽기, Nontransactional reads)

왜 데이터 수정은 발생하지 않을까?

트랜잭션 범위 밖에서 엔티티를 수정하면 영속성 컨텍스트의 변경 감지에 의한 데이터 수정이 일어나지 않을까?

  • 영속성 컨텍스트의 변경 내용을 데이터베이스에 저장하려면 flush해야 한다. 하지만 스프링 OSIV는 요청이 끝나면 close로 영속성 컨텍스트를 종료시킨다.
  • 표현 계층에서 flush를 강제 호출해도 트랜잭션 범위 밖이기 때문에 데이터를 수정할 수 없다는 예외가 발생한다. javax.persistence.TransactionRequiredException

단점

DB 커넥션을 영속성 컨텍스 종료시까지 1:1로 계속 유지한다.

영속성 컨텍스트의 유지로 트랜잭션 외부에서도 지연로딩을 사용할 수 있지만 너무 오래 데이터베이스의 커넥션 리소스를 사용하기 때문에 실시간 트래픽이 중요한 어플리케이션에서는 커넥션이 모자랄 수 있다.

즉, 컨트롤러에서 외부 API를 호출하면 외부 API 대기 시간만큼 커넥션 리소스를 반환하지 못하고 유지하는 것이다.

그럼 OSIV를 사용하지 않으면?

OSIV를 사용하지 않으면 트랜잭션을 종료할 때 영속성 컨텍스트를 닫고 데이터베이스 커넥션도 반환한다. 그렇기에 DB 커넥션 리소스를 낭비하지 않는다.

다만 OSIV를 사용하지 않으면 모든 지연로딩을 트랜잭션 내부에서 처리해야하기 때문에 모든 지연 로딩 코드를 트랜잭션 내부로 가져와야 한다. 또한 View Template이나 API 컨트롤러에서 지연로딩을 사용할 수 없다.

profile
제어할 수 없는 것에 의지하지 말자

0개의 댓글