JPA - OSIV(Open Session In View)

이진호·2023년 1월 11일
0

JPA

목록 보기
1/1

OSIV(Open Session In View)

  • 영속성 컨텍스트를 뷰까지 열어두는 기능.
  • 영속성 컨텍스트가 유지되면 엔티티도 영속 상태로 유지.
  • 뷰까지 영속성 컨텍스트가 살아있다면 뷰에서도 지연 로딩이 가능.

JPA에서는 OEIV(Open EntityManager In View), 하이버네이트에선 OSIV(Open Session In View)라고 함. 하지만 관례상 둘 다 OSIV로 부른다.

OSIV 동작 원리

  • 스프링 프레임워크가 제공하는 OSIV는 비즈니스 계층에서 트랜잭션을 사용하는 OSIV.
  • 영속성 컨텍스트는 사용자의 요청 시점에서 생성이 되지만, 데이터를 쓰거나 수정할 수 있는 트랜잭션은 비즈니스 계층에서만 사용할 수 있도록 트랜잭션이 생성.

OSIV 동작 원리

  • Spring Boot JPA 의존성을 주입 받아 어플리케이션을 구성할 경우 spring.jpa.open-in-view의 기본값인 true로 지정되어 있어 OSIV가 적용된 상태로 어플리케이션이 구성.

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

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

트랜잭션 없이 읽기(Nontransactional reads)

  • 서비스 계층에서 트랜잭션이 끝나면 컨트롤러와 뷰에는 트랜잭션이 유지되지 않는 상태.
  • 영속성 컨텍스트는 기본적으로 트랜잭션 범위 안에서 엔티티를 조회하고 수정할 수 있음.
  • 엔티티를 변경하지 않고 단순히 조회만 할 때는 트랜잭션이 없어도 동작함 트랜잭션 없이 읽기(Nontransactional reads)라 함.
  • 만약 프록시를 뷰 렌더링하는 과정에 초기화(Lazy loading)가 일어나게 되어도 조회 기능이므로 트랜잭션이 없이 읽기가 가능함.

만약 트랜잭션 범위 밖인 컨트롤러와 뷰에서 엔티티를 수정하여도 영속성 컨텍스트의 변경 감지에 의한 데이터 수정이 다음 2가지 이유로 동작하지 않는다.
1. 영속성 컨텍스트의 변경 내용을 데이터베이스에 반영하려면 영속성 컨텍스트를 플러시(flush)해야 하나, 스프링이 제공하는 OSIV는 요청이 끝나면 플러시를 호출하지 않고 em.close()로 영속성 컨텍스트만 종료시켜 버린다.
2. 프레젠테이션 계층에서 em.flush()를 호출하여 강제로 플러시해도 트랜잭션 범위 밖이므로 데이터를 수정할 수 없다는 예외가 일어난다. (javax.persistence.TransactionRequiredException)

OSIV 사용시 주의점

  • 지연 로딩은 영속성 컨텍스트가 살아있어야 가능하고, 영속성 컨텍스트는 기본적으로 데이터베이스 커넥션을 유지함.
  • OSIV 전략은 트랜잭션 시작처럼 최초 데이터베이스 커넥션 시작 시점부터 API 응답이 끝날 때 까지 영속성 컨텍스트와 데이터베이스 커넥션을 유지함. 그래서 View Template이나 API 컨트롤러에서 지연 로딩이 가능함.
  • 이 전략은 너무 오랜시간동안 데이터베이스 커넥션 리소스를 사용하기 때문에, 실시간 트래픽이 중요한 애플리케이션에서는 커넥션이 모자라게 되어 장애로 이어질 수 있음.
    • 예를 들어서 컨트롤러에서 외부 API를 호출하면 외부 API 대기 시간 만큼 커넥션 리소스를 반환하지 못하고, 유지해야 한다.
  • OISV의 치명적인 단점, 커넥션을 영속성 컨텍스트가 종료될 때까지 1:1로 계속 물고 있음

OSIV OFF

OSIV OFF

spring.jpa.open-in-view : false

  • OSIV를 끄면 트랜잭션을 종료할 때 영속성 컨텍스트를 닫고, 데이터베이스 커넥션도 반환함. 따라서 커넥션 리소스를 낭비하지 않음.
  • OSIV를 끄면 모든 지연로딩을 트랜잭션 안에서 처리해야 함. 따라서 지금까지 작성한 많은 지연 로딩 코드를 트랜잭션 안으로 넣어야 하는 단점이 있음. 또한 view template에서 지연로딩이 동작하지 않음.
  • 결론적으로 트랜잭션이 끝나기 전에 지연 로딩을 강제로 호출해 두어야 함.

커멘드와 쿼리 분리

  • OSIV를 끈 상태로 복잡성을 관리하는 좋은 방법. 바로 Command와 Query를 분리하는것.
  • Order
    • OrderService: 핵심 비즈니스 로직
    • OrderQueryService: 화면이나 API에 맞춘 서비스 (주로 읽기 전용 트랜잭션 사용)

출처

0개의 댓글