Czym jest właściwość this spring.jpa.open-in-view = true w Spring Boot?

121

Widziałem spring.jpa.open-in-view=truewłaściwość w dokumentacji Spring Boot dla konfiguracji JPA.

  • Czy jest to truewartość domyślna tej właściwości, jeśli w ogóle jej nie podano ?;
  • Co to naprawdę robi? Nie znalazłem dobrego wyjaśnienia tego;
  • Czy to sprawia, że ​​używasz SessionFactoryzamiast EntityManagerFactory? Jeśli tak, jak mogę to powiedzieć, aby umożliwić mi użycie EntityManagerFactoryzamiast tego?

Dzięki!

Carlos Alberto
źródło

Odpowiedzi:

52

Ta właściwość zarejestruje an OpenEntityManagerInViewInterceptor, który rejestruje an EntityManagerdo bieżącego wątku, więc będziesz mieć to samo EntityManagerdo zakończenia żądania internetowego. Nie ma to nic wspólnego z hibernacją SessionFactoryitp.

dunni
źródło
W tej chwili mam filtr OpenEntityManagerInViewFilter do kontrolowania EntityManager aż do zakończenia żądania internetowego. Ten przechwytywacz, który miałeś na myśli „OpenEntityManagerInViewInterceptor”, jest tym samym, co „OpenEntityManagerInViewFilter”? Jaka jest różnica między nimi? Więc nie chciałbym mieć więcej tego filtru w kontekście mojego serwletu dla Spring Boot?
Carlos Alberto
1
Interceptor działa tylko wtedy, gdy używasz DispatcherServlet w Spring (ponieważ przechwytywacz jest mechanizmem Spring). Filtr można odwzorować na wszystkie skonfigurowane serwlety (używamy go dla serwletu FacesServlet w jednej z naszych aplikacji). Więc jeśli używasz tylko DispatcherServlet, możesz dodać właściwość i usunąć filtr, w przeciwnym razie użyj filtru.
dunni
300

Anty-wzór OSIV

Zamiast pozwalać warstwie biznesowej decydować, w jaki sposób najlepiej pobrać wszystkie skojarzenia wymagane przez warstwę widoku, OSIV (otwarta sesja w widoku) wymusza, aby kontekst trwałości pozostał otwarty, aby warstwa widoku mogła wyzwolić inicjalizację serwera proxy, jak pokazano na ilustracji na poniższym schemacie.

wprowadź opis obrazu tutaj

  • OpenSessionInViewFilterWywołuje openSessionmetodę bazowego SessionFactoryi pozyskuje nowe Session.
  • SessionJest zobowiązany do TransactionSynchronizationManager.
  • OpenSessionInViewFilterNazywa doFiltersię javax.servlet.FilterChainodwołania do obiektu, a wniosek jest dalej przetwarzany
  • DispatcherServletNazywa i IT kieruje żądania HTTP do instrumentu bazowego PostController.
  • W PostControllerwywołuje PostServiceuzyskać listę Postpodmiotów.
  • PostServiceOtwiera nową transakcję i HibernateTransactionManagerponownie wykorzystuje ten sam Session, który został otwarty przez OpenSessionInViewFilter.
  • PostDAOPobiera listę Postpodmiotów bez inicjowania żadnej leniwe stowarzyszenie.
  • Zatwierdza PostServicetransakcję bazową, ale Sessionnie jest zamknięta, ponieważ została otwarta na zewnątrz.
  • Do DispatcherServletrozpoczyna renderowania interfejsu użytkownika, który z kolei nawiguje leniwe skojarzenia i wyzwala ich inicjalizacji.
  • OpenSessionInViewFilterMożna zamknąć Session, a pod spodem połączenie z bazą danych jest zwolniony także.

Na pierwszy rzut oka może to nie wyglądać na straszne, ale gdy spojrzysz na to z perspektywy bazy danych, seria błędów staje się bardziej oczywista.

Warstwa usług otwiera i zamyka transakcję bazy danych, ale później nie ma żadnej jawnej transakcji. Z tego powodu każda dodatkowa instrukcja wydana z fazy renderowania interfejsu użytkownika jest wykonywana w trybie automatycznego zatwierdzania. Automatyczne zatwierdzanie wywiera presję na serwer bazy danych, ponieważ każda instrukcja musi opróżnić dziennik transakcji na dysk, powodując w ten sposób duży ruch we / wy po stronie bazy danych. Jedną z optymalizacji byłoby oznaczenie Connectionjako tylko do odczytu, co pozwoliłoby serwerowi bazy danych uniknąć zapisywania w dzienniku transakcji.

Nie ma już rozdzielania obaw, ponieważ instrukcje są generowane zarówno przez warstwę usług, jak i przez proces renderowania interfejsu użytkownika. Pisanie testów integracyjnych, które potwierdzają liczbę generowanych instrukcji, wymaga przejścia przez wszystkie warstwy (sieć, usługa, DAO) podczas wdrażania aplikacji w kontenerze internetowym. Nawet w przypadku korzystania z bazy danych w pamięci (np. HSQLDB) i lekkiego serwera WWW (np. Jetty), te testy integracyjne będą wykonywane wolniej, niż gdyby warstwy były rozdzielane, a testy integracji zaplecza korzystały z bazy danych, podczas gdy testy integracji front-endu w ogóle kpili z warstwy usług.

Warstwa interfejsu użytkownika jest ograniczona do nawigacji po asocjacjach, które z kolei mogą powodować problemy z zapytaniami N + 1 . Chociaż Hibernate oferuje @BatchSizepobieranie skojarzeń w partiach i FetchMode.SUBSELECTporadzi sobie z tym scenariuszem, adnotacje wpływają na domyślny plan pobierania, więc są stosowane w każdym biznesowym przypadku użycia. Z tego powodu kwerenda warstwy dostępu do danych jest o wiele bardziej odpowiednia, ponieważ można ją dostosować do aktualnych wymagań dotyczących pobierania danych dla przypadków użycia.

Wreszcie, połączenie z bazą danych jest utrzymywane przez całą fazę renderowania interfejsu użytkownika, co wydłuża czas dzierżawy połączenia i ogranicza ogólną przepustowość transakcji z powodu przeciążenia puli połączeń bazy danych. Im dłużej połączenie jest utrzymywane, tym więcej innych współbieżnych żądań będzie czekać na połączenie z puli.

Spring Boot i OSIV

Niestety, OSIV (Open Session in View) jest domyślnie włączony w Spring Boot , a OSIV to naprawdę zły pomysł z punktu widzenia wydajności i skalowalności .

Dlatego upewnij się, że w application.propertiespliku konfiguracyjnym znajduje się następujący wpis:

spring.jpa.open-in-view=false

Spowoduje to wyłączenie OSIV, abyś mógł sobie poradzić LazyInitializationExceptionwe właściwy sposób .

Począwszy od wersji 2.0, Spring Boot wyświetla ostrzeżenie, gdy OSIV jest domyślnie włączony, więc możesz wykryć ten problem na długo przed tym, zanim wpłynie on na system produkcyjny.

Więcej informacji na temat OSIV można znaleźć w tym artykule .

Vlad Mihalcea
źródło
14
Obecnie rejestrowane jest OSTRZEŻENIE.
Vlad Mihalcea
Czy dotyczy to ogólnie wiosny, czy tylko Spring Boot? Czy można to wyłączyć za pomocą klasy z adnotacjami @ Configuration zamiast ustawiania właściwości?
Gordon
2
Dotyczy tylko Spring Boot. W standardowej wersji Spring możesz wyraźnie wybrać, jakie ziarna mają być używane, lub czy chcesz filtr sieciowy, taki jak OSIV. Nie wiem, czy możesz to wyłączyć za pomocą jakiejś adnotacji. Wiem tylko o ustawieniach konfiguracyjnych.
Vlad Mihalcea,
To nie jest anty-wzór. Ma to wpływ na wydajność, czasami negatywny, często całkiem neutralny, aw wielu przypadkach w pozytywny sposób: jeśli naprawdę chcesz zacząć leniwą relację, nie musisz wykonywać zapytania we wszystkich przypadkach i można tego uniknąć w razie potrzeby, korzystając z funkcji Open-in-View.
ymajoros
5
Według Wikipedii „anty-wzorce to powszechna odpowiedź na powracający problem, który jest zwykle nieskuteczny i może przynieść duże skutki odwrotne do zamierzonych”. Właśnie tym jest otwarta sesja w widoku.
Vlad Mihalcea