回答:
このプロパティは、現在のスレッドOpenEntityManagerInViewInterceptor
にを登録するEntityManager
を登録するためEntityManager
、Webリクエストが完了するまで同じです。Hibernate SessionFactory
などとは関係ありません。
図に示すように、ビジネスレイヤーにビューレイヤーで必要なすべての関連付けを取得するのに最適な方法を決定させる代わりに、OSIV(ビューでセッションを開く)は、ビューレイヤーがプロキシの初期化をトリガーできるように、永続コンテキストを強制的に開いたままにします。次の図によって。
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
今度は、遅延関連付けをナビゲートし、その初期化をトリガー、UIを、レンダリングを開始。OpenSessionInViewFilter
を閉じることができSession
、基になるデータベース接続も解放されます。一見すると、これはひどいことのようには見えないかもしれませんが、データベースの観点から見ると、一連の欠陥がより明白になります。
サービス層はデータベーストランザクションを開いたり閉じたりしますが、その後は明示的なトランザクションは発生しません。このため、UIレンダリングフェーズから発行される追加のステートメントはすべて、自動コミットモードで実行されます。各ステートメントはトランザクションログをディスクにフラッシュする必要があるため、自動コミットはデータベースサーバーに負荷をかけ、データベース側で大量のI / Oトラフィックを引き起こします。最適化の1つはConnection
、データベースサーバーがトランザクションログへの書き込みを回避できるように、読み取り専用としてマークすることです。
ステートメントはサービスレイヤーとUIレンダリングプロセスの両方で生成されるため、問題の分離はもうありません。生成されるステートメントの数をアサートする統合テストを作成するには、アプリケーションをWebコンテナーにデプロイしながら、すべてのレイヤー(Web、サービス、DAO)を通過する必要があります。インメモリデータベース(HSQLDBなど)と軽量Webサーバー(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以降、OSがデフォルトで有効になっている場合、Spring Boot は警告を発行するため、本番システムに影響するずっと前にこの問題を発見できます。
OSIVの詳細については、こちらの記事をご覧ください。