ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [스프링] OSIV
    스프링 2022. 12. 28. 16:49
    728x90
    김영한님의 자바 ORM 표준 JPA 프로그래밍에 기반되어 작성되었습니다 ( 책 추천합니다! )

     

    1. JPA 내부 동작 방식

     

    트랜잭션 범위 == 영속성 컨텍스트의 생존 범위

    -> 트랜잭션이 시작할 때 영속성 컨텍스트를 생성하고, 트랜잭션이 끝날 때 영속성 컨텍스트를 종료한다

     

    비즈니스 로직을 시작하는 서비스 계층에서 @Transactional 선언해서 트랜잭션을 시작한다.

    이 애노테이션이 있으면 호출한 메소드 실행 직전에 스프링 트랜잭션 AOP 먼저 동작

     

    AOP 실행위치

    간단 정리,
    트랜잭션 AOP -> transaction 커밋해서 영속성 컨텍스트 플러스해서 DB 반영O or transaction 롤백해서 DB 반영 X

     

    참고로, 트랜잭션이 같으면 다른 엔티티 매니저를 주입받아도 같은 영속성 컨텍스트를 사용한다 ( transaction이 같아? 그러면 영속성 컨텍스트도 같아)

    같은 영속성 컨텍스트 사용

     

    2. 준영속과 지연로딩!!

    준영속은 영속성 컨텍스트에 의해서 관리 받지 않기에 지연로딩이 발생하지 않는다.

    OSIV 사용하는 이유 : 서비스 계층과는 달리 컨트롤러랑 뷰같은 프리젠테이션 계층은 준영속 상태여서 지연로딩이 되지 않는다. 

     

    참고, 프레젠테이션 부분 => 컨트롤러랑 뷰 부분을 의미한다

     

     

    프레젠테이션에서 지연로딩 하는 방법 1) 뷰가 필요한 엔티티 미리 로딩

     

    1. 글로벌 페치 전략 수정 : 지연을 즉시로딩으로 변경 -> N+1, 사용하지 않는 엔티티 로딩되는 문제

    2. JPQL 페치 조인 : 현실적이지만, 무분별하게 사용되면 데이터 접근 계층 침범

    3. 강제로 초기화 : Facade 계층을 두어서 해결할 수 있지만, 중간에 계층이 한개 더 생기는 불편함

     

    결론, 모든 문제는 엔티티가 프리젠테이션 계층에서 준영속 상태여서 발생하는 것!

     

     

    프레젠테이션에서 지연로딩 하는 방법 2) OSIV로 엔티티를 영속 상태로 유지

    OSIV : 영속성 컨텍스트를 뷰까지 열어둔다는 뜻 ( 영속성 켄텍스트가 살아있으니 엔티티는 영속 상태 유지 )
    핵심, 뷰에서도 지연로딩이 가능하도록 하는 것입니다.

     

    과거 OSIV는 요청당 트랜잭션이였다.

    CLI로 부터 요청을 받으면, 동시에 트랜잭션을 시작하여서 영속성 컨텍스트를 유지했는데, 프리젠테이션[ 컨트롤러, 뷰 ] 부분에서 엔티티를 수정할 수 있다는 문제점 발생.

     

    이를 해결하는 방법은 3가지

     

    1. 엔티티를 읽기 전용 인터페이스로 제공

    2. 엔티티 레핑

    3. DTO로 반환 ( 가장 전통적인데, 단순히 데이터만 전달하는 객체인 DTO를 생성해서 반환하는데, 이는 OSIV 장점을 살리지 못함 )

     

     

    현재 OSIV는 비즈니스 계층 트랜잭션이다

     

    특징

    1. 영속성 컨텍스트를 프리젠테이션 계층까지 유지

    2. 프리젠테이션 계층에는 트랜잭션이 없으므로 엔티티 수정 불가능

    3. 프리젠테이션 계층에는 트랜잭션이 없지만, 트랜잭션 없이 읽기를 통해 지연 로딩 가능

     

     

    현재 OSIV

    1. CLI 요청

    2. 서블릿 필터 or 스프링 인터셉트에서 영속성 컨텍스트 생성 ( Transaction은 하지 않는다 )

    3. 서비스 계층에서 @Transactional시작시, 위에서 만든 영속성 컨텍스트 가져와서 트랜잭션 시작

    4. 서비스 계층 끝나면, 트랜잭션 커밋 -> 플러시하여서 트랜잭션은 끝내지만, 영속성 컨텍스트는 유지

    5. 서블릿 필터 or 스프링 인터셉트로 요청이 들어오면 플러시 호출 하지 않고, 바로 영속성 컨텍스트 종료

     

    과거의 엔티티를 수정할 수 있다는 문제는 트랜잭션 없이 읽기 를 통해서 해결 가능

    트랜잭션 없이 읽기 - 영속성 컨택스트를 통한 모든 변경을 트랜잭션 안에서 이뤄져야 하므로, 트랜잭션이 없이는 단순 조회(읽기)만 가능하다.

     

    주의 사항 : 프리젠테이션 계층에서 엔티티 수정한 직후 Transaction 시작하는 서비스 계층 호출 시 문제

    -> Transaction 있는 비즈니스 로직을 모두 호출하고 나서 엔티티 변경하면 된다

     

    3. OSIV 정리

    1) 스프링 OSIV 특징

    1. CLI 요청이 들어올 때 영속성 컨텍스트 생성해서 요청이 끝날 때까지 같은 영속성 컨텍스트 유지

    2. 엔티티 수정은 트랜잭션이 있는 계층에서만!

     

    2) 스프링 OSIV 단점

    1. 영속성 컨텍스트를 여러 트랜잭션이 공유할 수 있다는 점 ( 롤백시 주의 )

    2. 프리젠테이션 계층에서 엔티티 수정후 비즈니스 로직 호출시 문제(  비즈니스 로직을 모두 호출하고 나서 엔티티 변경하기 )

    3. 프리젠테이션 계층에서 지연로딩에 의한 SQL 실행되니까 성능 튜닝시 체크하기

     

    Open-in-view

    는 JPA에서 영속성 컨텍스트가 데이터베이스 커넥션을 DB에 언제 돌려주냐를 설정할 수 있다.

     

    해당 메소드가 끝이 날 때

    spring.jpa.open-in-view=true 면 영속성 컨텍스트가 데이터베이스 커넥션을 반납하지않고, Client에게 응답이 되고 난 후에 DB 커넥션을 반납한다. ❗

    spring.jpa.open-in-view=false 면 영속성 컨텍스트가 데이터베이스 커넥션을 반납한다.

     

    open-in-view 사용 용도

    true 사용 하는 경우 

    어드민 같은 사용량이 많지 않은 경우는 true로 사용하여 지연로딩을 @Transactional 을 벗어난 곳에서도 할 수 있는 유연함을 챙길 수 있다. 

     

    false 사용 하는 경우

    사용량이 많은 서비스를 제공하는 어플리케이션 에서는 false로 두어 DB 커넥션을 바로 반납하게 하여, 마르지 않도록 하는 것이 좋으며,

    대신  @Transaciotnal이 붙은 메소드 안에서 (필요에 따라) 지연로딩과 관련 초기화를 전부 시켜줘야 한다. 

    https://livelyoneweek.tistory.com/m/57

     

    spring.jpa.open-in-view 란?

    스프링 부트로 프로젝트로 만들고 실행을 시키면, WARN 이 하나 나온다. (spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explictily configure spring.jpa.open-in-view t

    livelyoneweek.tistory.com

     

Designed by Tistory.