Eine längere Beschreibung finden Sie in meinem Artikel " Open Session In View Anti-Pattern ". Andernfalls finden Sie hier eine Zusammenfassung, warum Sie Open Session In View nicht verwenden sollten.
Open Session In View verfolgt einen schlechten Ansatz beim Abrufen von Daten. Anstatt die Geschäftsschicht entscheiden zu lassen, wie alle Zuordnungen, die von der Ansichtsebene benötigt werden, am besten abgerufen werden, wird der Persistenzkontext geöffnet, damit die Ansichtsebene die Proxy-Initialisierung auslösen kann.
- Der
OpenSessionInViewFilter
ruft die openSession
Methode des Basiswerts auf SessionFactory
und erhält eine neue Session
.
- Das
Session
ist an das gebunden TransactionSynchronizationManager
.
- Das
OpenSessionInViewFilter
ruft die doFilter
die javax.servlet.FilterChain
Objektreferenz und die Anforderung wird weiter verarbeitet
- Das
DispatcherServlet
wird aufgerufen und leitet die HTTP-Anforderung an den Basiswert weiter PostController
.
- Das
PostController
ruft das PostService
auf, um eine Liste der Post
Entitäten zu erhalten.
- Das
PostService
öffnet eine neue Transaktion und das HibernateTransactionManager
wiederverwendet das gleiche Session
, das von der geöffnet wurde OpenSessionInViewFilter
.
- Der
PostDAO
ruft die Liste der Post
Entitäten ab, ohne eine verzögerte Zuordnung zu initialisieren.
- Das
PostService
schreibt die zugrunde liegende Transaktion fest, wird jedoch Session
nicht geschlossen, da sie extern geöffnet wurde.
- Das
DispatcherServlet
Rendering der Benutzeroberfläche beginnt, die wiederum durch die verzögerten Zuordnungen navigiert und deren Initialisierung auslöst.
- Das
OpenSessionInViewFilter
kann die schließen Session
, und die zugrunde liegende Datenbankverbindung wird ebenfalls freigegeben.
Auf den ersten Blick mag dies nicht schrecklich aussehen, aber sobald Sie es aus einer Datenbankperspektive betrachten, werden eine Reihe von Fehlern offensichtlicher.
Die Serviceschicht öffnet und schließt eine Datenbanktransaktion, danach findet jedoch keine explizite Transaktion statt. Aus diesem Grund wird jede zusätzliche Anweisung aus der UI-Rendering-Phase im Auto-Commit-Modus ausgeführt. Das automatische Festschreiben übt Druck auf den Datenbankserver aus, da jede Anweisung das Transaktionsprotokoll auf die Festplatte leeren muss, wodurch auf der Datenbankseite viel E / A-Verkehr verursacht wird. Eine Optimierung wäre, das Connection
als schreibgeschützt zu markieren, wodurch der Datenbankserver das Schreiben in das Transaktionsprotokoll vermeiden kann.
Es gibt keine Trennung von Bedenken mehr, da Anweisungen sowohl von der Service-Schicht als auch vom UI-Rendering-Prozess generiert werden. Das Schreiben von Integrationstests, die die Anzahl der generierten Anweisungen bestätigen, erfordert das Durchlaufen aller Ebenen (Web, Service, DAO), während die Anwendung auf einem Webcontainer bereitgestellt wird. Selbst wenn eine In-Memory-Datenbank (z. B. HSQLDB) und ein leichtgewichtiger Webserver (z. B. Jetty) verwendet werden, werden diese Integrationstests langsamer ausgeführt als wenn Schichten getrennt würden und die Back-End-Integrationstests die Datenbank verwenden würden, während die Front-End-Integrationstests verspotteten die Service-Schicht insgesamt.
Die UI-Ebene ist auf das Navigieren in Assoziationen beschränkt, was wiederum N + 1-Abfrageprobleme auslösen kann. Obwohl Hibernate Angebote @BatchSize
zum Abrufen von Zuordnungen in Stapeln und FetchMode.SUBSELECT
zur Bewältigung dieses Szenarios anbietet , wirken sich die Anmerkungen auf den Standardabrufplan aus, sodass sie auf jeden Geschäftsanwendungsfall angewendet werden. Aus diesem Grund ist eine Datenzugriffsschichtabfrage viel besser geeignet, da sie auf die aktuellen Anforderungen für das Abrufen von Anwendungsfalldaten zugeschnitten werden kann.
Last but not least kann die Datenbankverbindung während der gesamten Rendering-Phase der Benutzeroberfläche (abhängig von Ihrem Verbindungsfreigabemodus) gehalten werden, wodurch die Verbindungslease-Zeit verlängert und der gesamte Transaktionsdurchsatz aufgrund einer Überlastung des Datenbankverbindungspools begrenzt wird. Je länger die Verbindung gehalten wird, desto mehr andere gleichzeitige Anforderungen warten darauf, eine Verbindung aus dem Pool zu erhalten.
Entweder wird die Verbindung zu lange gehalten, oder Sie erwerben / geben mehrere Verbindungen für eine einzelne HTTP-Anforderung frei, wodurch der zugrunde liegende Verbindungspool unter Druck gesetzt und die Skalierbarkeit eingeschränkt wird.
Frühlingsstiefel
Leider ist Open Session in View in Spring Boot standardmäßig aktiviert .
Stellen Sie also sicher, dass Sie in der application.properties
Konfigurationsdatei den folgenden Eintrag haben:
spring.jpa.open-in-view=false
Dies wird deaktivieren OSIV, so dass Sie den Griff , LazyInitializationException
den richtigen Weg .