답변:
이 속성은 현재 스레드에 OpenEntityManagerInViewInterceptor
를 등록하는를 등록 EntityManager
하므로 EntityManager
웹 요청이 완료 될 때까지 동일한 속성을 갖게됩니다 . Hibernate SessionFactory
등과 는 관련이 없습니다 .
비즈니스 계층이 View 계층에 필요한 모든 연결을 가져 오는 것이 가장 좋은 방법을 결정하도록하는 대신 OSIV (Open Session in View)는 그림과 같이 View 계층이 프록시 초기화를 트리거 할 수 있도록 Persistence Context를 강제로 열어 둡니다. 다음 다이어그램으로.
OpenSessionInViewFilter
부르는 openSession
기본 방법을 SessionFactory
새로운를 가져옵니다 Session
.Session
에 바인딩됩니다 TransactionSynchronizationManager
.OpenSessionInViewFilter
부르는 doFilter
의 javax.servlet.FilterChain
오브젝트 레퍼런스 및 요청이 더 처리DispatcherServlet
라고하며 기본에이를 라우팅 HTTP 요청한다 PostController
.PostController
통화량은 PostService
목록을 얻을 수 Post
개체를.PostService
새 트랜잭션을 열고,이 HibernateTransactionManager
같은 재사용 Session
에 의해 열린이 OpenSessionInViewFilter
.PostDAO
목록 가져 오는 Post
어떤 게으른 관계를 초기화하지 않고 개체를.PostService
기본 트랜잭션을 커밋하지만은 Session
그것이 외부에서 열렸다 때문에 닫히지 않았습니다.DispatcherServlet
차례로, lazy 연관을 탐색하고 자신의 초기화를 트리거 UI를 렌더링이 시작됩니다.OpenSessionInViewFilter
을 닫을 수 Session
및 기본 데이터베이스 연결이 잘으로 해제됩니다.언뜻보기에 이것은 끔찍한 일처럼 보이지 않을 수도 있지만 데이터베이스 관점에서 보면 일련의 결함이 더 분명해지기 시작합니다.
서비스 계층은 데이터베이스 트랜잭션을 열고 닫지 만 이후에는 명시적인 트랜잭션이 진행되지 않습니다. 이러한 이유로 UI 렌더링 단계에서 발행 된 모든 추가 문은 자동 커밋 모드에서 실행됩니다. 자동 커밋은 각 문이 트랜잭션 로그를 디스크로 플러시해야하므로 데이터베이스 측에서 많은 I / O 트래픽을 유발하므로 데이터베이스 서버에 부담을줍니다. 한 가지 최적화는를 Connection
읽기 전용으로 표시 하여 데이터베이스 서버가 트랜잭션 로그에 쓰지 않도록하는 것입니다.
문은 서비스 계층과 UI 렌더링 프로세스 모두에서 생성되기 때문에 더 이상 문제가 분리되지 않습니다. 생성되는 문 수를 확인하는 통합 테스트를 작성 하려면 애플리케이션이 웹 컨테이너에 배포되는 동안 모든 계층 (웹, 서비스, DAO)을 거쳐야합니다. 인 메모리 데이터베이스 (예 : HSQLDB) 및 경량 웹 서버 (예 : Jetty)를 사용하는 경우에도 이러한 통합 테스트는 계층이 분리되고 백엔드 통합 테스트에서 데이터베이스를 사용하는 경우보다 실행 속도가 느립니다. 프런트 엔드 통합 테스트는 서비스 계층을 모두 조롱했습니다.
UI 레이어는 N + 1 쿼리 문제를 유발할 수있는 연결 탐색으로 제한됩니다 . Hibernate는 @BatchSize
일괄 적으로 연관을 가져오고이 FetchMode.SUBSELECT
시나리오에 대처하기 위해 제공하지만 주석은 기본 가져 오기 계획에 영향을 미치므로 모든 비즈니스 사용 사례에 적용됩니다. 이러한 이유로 데이터 액세스 계층 쿼리는 현재 사용 사례 데이터 가져 오기 요구 사항에 맞게 조정할 수 있기 때문에 훨씬 더 적합합니다.
마지막으로 데이터베이스 연결은 UI 렌더링 단계 내내 유지되므로 연결 임대 시간이 늘어나고 데이터베이스 연결 풀의 정체로 인해 전체 트랜잭션 처리량이 제한됩니다. 연결이 더 많이 유지 될수록 풀에서 연결을 얻기 위해 더 많은 다른 동시 요청이 대기하게됩니다.
불행히도 OSIV (Open Session in View)는 Spring Boot에서 기본적으로 활성화되어 있으며 OSIV는 성능 및 확장 성 관점에서 볼 때 실제로 나쁜 생각입니다 .
따라서 application.properties
구성 파일에 다음 항목이 있는지 확인하십시오 .
spring.jpa.open-in-view=false
이렇게하면 OSIV가 비활성화 되어 올바른 방법으로 처리LazyInitializationException
할 수 있습니다 .
버전 2.0부터는 OSIV 가 기본적으로 활성화 되면 Spring Boot 가 경고를 발행 하므로 프로덕션 시스템에 영향을 미치기 훨씬 전에이 문제를 발견 할 수 있습니다.