programing

View에서 휴지 상태 열기 세션이 잘못된 관행으로 간주되는 이유는 무엇입니까?

yoursource 2023. 2. 4. 10:13
반응형

View에서 휴지 상태 열기 세션이 잘못된 관행으로 간주되는 이유는 무엇입니까?

또한 Lazy Load Exceptions를 피하기 위해 어떤 대체 전략을 사용합니까?

현재 오픈 세션은 다음과 같은 문제가 있는 것으로 알고 있습니다.

  • 서로 다른 jvm에서 실행되는 계층형 애플리케이션
  • 트랜잭션은 마지막에만 커밋되며, 대부분의 경우 이전 결과를 원할 수 있습니다.

그러나 애플리케이션이 단일 VM에서 실행되고 있다는 것을 알고 있다면 개방형 세션(View 전략)을 사용하여 문제를 해결하십시오.

Open Session In View는 데이터 가져오기에 잘못된 접근 방식을 취합니다.View 계층에 필요한 모든 연결을 가져오는 최선의 방법을 비즈니스 계층이 결정하는 대신 View 계층이 프록시 초기화를 트리거할 수 있도록 지속성 컨텍스트를 강제로 열어 둡니다.

여기에 이미지 설명 입력

  • OpenSessionInViewFilter라고 부르다openSession가 되는 ★★★★★★★★★★★★★★」SessionFactory 수 있습니다.Session.
  • Session는 에 바인드되어 있습니다.
  • OpenSessionInViewFilter라고 부르다doFilterjavax.servlet.FilterChain 및 됩니다.
  • 가 호출되어 HTTP 요구를 기본에 라우팅합니다.PostController.
  • PostController라고 부르다PostServicePost엔티티
  • PostService " " " 가 열립니다.HibernateTransactionManager 을 재사용하다Session에 의해 OpenSessionInViewFilter.
  • PostDAOPost★★★★★★★★★★★★★★★★★★.
  • PostService만, 「」는 「」입니다.Session외부로 열려 있기 때문에 닫히지 않습니다.
  • DispatcherServlet는 UI 렌더링을 시작하고, 그 결과 느린 연관성을 탐색하여 초기화를 트리거합니다.
  • OpenSessionInViewFilter 수 .Session이치노

언뜻 보기에는 그렇게 나쁘지 않은 것처럼 보이지만 일단 데이터베이스 관점에서 보면 일련의 결함이 더욱 분명해지기 시작합니다.

서비스 계층은 데이터베이스 트랜잭션을 열고 닫지만 이후에는 명시적인 트랜잭션이 진행되지 않습니다.따라서 UI 렌더링 단계에서 발행된 추가 문은 모두 자동 커밋 모드로 실행됩니다.자동 커밋은 각 문이 트랜잭션 로그를 디스크에 플러시해야 하므로 데이터베이스 서버에 부담을 줍니다. 따라서 데이터베이스 측에서 많은 I/O 트래픽이 발생합니다. 가지 는 '를 붙이는 것'입니다.Connection읽기 전용으로 지정하면 데이터베이스 서버가 트랜잭션 로그에 쓰지 않아도 됩니다.

문장은 서비스 계층과 UI 렌더링 프로세스 모두에서 생성되므로 더 이상 문제를 분리할 수 없습니다.생성되는 문의 수를 나타내는 통합 테스트를 작성하려면 응용 프로그램을 웹 컨테이너에 배치하면서 모든 계층(웹, 서비스, DAO)을 거쳐야 합니다.인메모리 데이터베이스(HSQLDB 등)와 경량 웹 서버(Jetty 등)를 사용하는 경우에도 이러한 통합 테스트는 레이어가 분리되어 백엔드 통합 테스트가 데이터베이스를 사용하는 경우보다 실행 속도가 느립니다.또한 프론트 엔드 통합 테스트는 서비스 레이어를 완전히 조롱하고 있습니다.

UI 계층은 N+1 쿼리 문제를 트리거할 수 있는 탐색 연결로 제한됩니다.Hibernate는 어소시에이션을 일괄적으로 취득할 수 있는 기능을 제공하지만 이 시나리오에 대응하기 위해 주석은 기본 취득 계획에 영향을 미치기 때문에 모든 비즈니스 사용 사례에 적용됩니다.따라서 데이터 액세스 레이어 쿼리는 현재의 유스케이스 데이터 취득 요건에 맞추어 커스터마이즈할 수 있기 때문에 훨씬 적합합니다.

마지막으로 데이터베이스 접속은 UI 렌더링 단계(접속릴리스 모드에 따라 다름) 내내 유지되므로 접속 리스 시간이 길어지고 데이터베이스 접속 풀의 폭주로 인해 전체적인 트랜잭션 처리량이 제한됩니다.연결이 보류될수록 다른 동시 요청은 풀에서 연결을 얻기 위해 더 많이 대기합니다.

따라서 접속이 너무 오래 유지되거나 단일 HTTP 요구에 대해 여러 연결을 취득 또는 해제하여 기본 연결 풀에 부담이 되고 확장성이 제한됩니다.

스프링 부트

안타깝게도 Spring Boot에서는 Open Session in View가 기본적으로 활성화되어 있습니다.

때문에 이 안에 것을 .application.properties설정 파일의 엔트리는 다음과 같습니다.

spring.jpa.open-in-view=false

를 처리할 수 .LazyInitializationException하는 것으로, 「어소시에이션」은 「어소시에이션」으로 합니다.EntityManager려려있있있있다다

뷰 레이어에서 초기화되지 않은 프록시(특히 컬렉션)를 전송하고 거기서부터 휴지 상태 로드를 트리거하는 것은 퍼포먼스와 이해의 관점에서 모두 문제가 될 수 있습니다.

이해:

OSIV를 사용하면 데이터 액세스 계층과 관련된 문제로 뷰 계층을 '오염'시킬 수 있습니다.

가 처리 않습니다.HibernateException로딩이 느릴 때 발생할 수 있지만 데이터 액세스레이어는 아마 그렇습니다.

퍼포먼스:

OSIV는 적절한 엔티티 로드를 카펫 아래로 끌어당기는 경향이 있습니다.컬렉션이나 엔티티가 느긋하게 초기화되어 있는 것을 눈치채지 못하는 경향이 있습니다(아마 N+1).편의성은 높이고 제어력은 낮습니다.


업데이트: Open Session 참조 주제에 대한 자세한 내용은 InView를 참조하십시오.저자는 세 가지 중요한 점을 열거하고 있다.

  1. 각 지연 초기화는 N + 1 쿼리를 각 엔티티에 필요함을 의미합니다.여기서 N은 지연 어소시에이션의 수입니다.화면에 표 형식의 데이터가 표시되어 있는 경우, 휴지 상태의 로그를 읽는 것은, 필요한 대로 하지 않는 것을 나타내는 큰 힌트입니다.
  2. 이는 프레젠테이션 계층에서 DB를 사용하여 문제를 해결하므로 계층형 아키텍처를 완전히 배제합니다.이건 개념적인 결말이기 때문에 감수할 수 있지만 그에 따른 결과가 있습니다.
  3. 마지막으로 세션을 가져오는 동안 예외가 발생하면 페이지 쓰기 중에 발생합니다. 사용자에게 깨끗한 오류 페이지를 제공할 수 없으며 본문에 오류 메시지를 쓰는 것밖에 할 수 없습니다.
  • 트랜잭션은 서비스 계층에서 커밋할 수 있습니다. OSIV를 사용하다★★★★★★★★★★★★★★★★★★입니다Session트랜잭션 실행이 아닌 열린 상태로 유지됩니다.

  • 애플리케이션 레이어가 여러 머신에 분산되어 있는 경우 OSIV를 거의 사용할 없습니다.오브젝트를 회선으로 송신하기 전에 필요한 모든 것을 초기화해야 합니다.

  • OSIV는 느린 로딩의 퍼포먼스 이점을 활용할 수 있는 뛰어난 투과적 방법(즉, 코드 중 어느 것도 그것을 인식하지 않음)입니다.

Open Session In View가 나쁜 관행이라고는 할 수 없습니다. 어떤 점이 그렇게 생각하시나요?

Open-Session-In-View는 휴지 상태에서의 세션을 처리하는 간단한 방법입니다.단순하기 때문에 때로는 단순하기도 합니다.요청에 여러 트랜잭션을 포함하는 등 트랜잭션을 세밀하게 제어해야 하는 경우 Open-Session-In-View가 항상 좋은 접근 방식은 아닙니다.

다른 사람들이 지적한 바와 같이 OSIV에는 몇 가지 트레이드오프가 있습니다.어떤 트랜잭션을 시작하는지 인식할 가능성이 낮기 때문에 N+1 문제가 발생하기 쉽습니다.동시에 뷰의 사소한 변경에 적응하기 위해 서비스 계층을 변경할 필요가 없습니다.

Spring과 같은 IoC(Inversion of Control) 컨테이너를 사용하는 경우 콩 스코핑에 대해 자세히 알아볼 수 있습니다.본질적으로, 나는 봄에게 나에게 겨울잠을 자라고 말하고 있다.Session라이프 사이클이 요구 전체에 걸치는 오브젝트(즉, HTTP 요청의 시작과 종료 시에 생성 및 파기됩니다)..LazyLoadExceptionIoC 컨테이너가 이를 관리하므로 세션을 닫지도 않습니다.

전술한 바와 같이 N+1 SELECT의 퍼포먼스 문제에 대해 생각해야 합니다.하이버네이트 엔티티는 나중에 언제든지 퍼포먼스가 문제가 되는 장소에서 고속 결합 로드를 실행하도록 설정할 수 있습니다.

콩의 범위 지정 솔루션은 스프링 고유의 솔루션이 아닙니다.Pico Container도 같은 기능을 제공한다는 것을 알고 있으며, 다른 성숙한 IoC 컨테이너도 이와 비슷한 기능을 제공한다고 확신합니다.

제 경험상 OSIV는 나쁘지 않습니다.제가 한 유일한 준비는 두 가지 트랜잭션을 사용하는 것입니다.첫 번째는 "서비스 계층"에서 열었고, 첫 번째는 "비즈니스 로직"에서 열었습니다. 두 번째는 뷰 렌더링 직전에 열었습니다.

오픈 세션의 이용 시기에 관한 가이드라인을 블로그에 투고했습니다.관심있으시면 확인해보세요.

http://heapdump.wordpress.com/2010/04/04/should-i-use-open-session-in-view/

난 겨울잠에서 녹슬었어..하지만 한 번의 휴지기 세션에서 여러 번 트랜잭션을 수행할 수 있다고 생각합니다.따라서 트랜잭션 경계가 세션 시작/중지 이벤트와 같을 필요는 없습니다.

OSIV, imo는 주로 도움이 됩니다.요구가 DB에 액세스해야 할 때마다 '지속 컨텍스트'(일명 세션)를 시작하기 위한 코드를 쓰지 않아도 되기 때문입니다.

서비스 계층에서는 'Required', 'New Required' 등 트랜잭션 요구가 다른 메서드를 호출해야 합니다.이 메서드에 필요한 것은 누군가(OSIV 필터)가 퍼시스텐스 콘텍스트를 기동하고 있기 때문에, 이 스레드에 대해 「헤이, 휴지 상태의 세션을 주세요.DB 작업을 해야 합니다.

이것은 그다지 도움이 되지 않습니다만, 다음의 토픽을 참조해 주세요.* Open Session을 사용한 캐시 1 Out Of Memory인뷰

Open Session으로 인해 메모리 부족 문제가 발생했습니다.InView 및 많은 엔티티가 로드됩니다.이는 엔티티가 휴지 상태 캐시 레벨 1에 머무르고 가비지 수집이 되지 않기 때문입니다(페이지당 500개의 아이템이 있는 엔티티를 로드하지만 모든 엔티티는 캐시에 남습니다).

언급URL : https://stackoverflow.com/questions/1103363/why-is-hibernate-open-session-in-view-considered-a-bad-practice

반응형