Pour une description plus longue, vous pouvez lire mon article Open Session In View Anti-Pattern . Sinon, voici un résumé des raisons pour lesquelles vous ne devriez pas utiliser Open Session In View.
Open Session In View adopte une mauvaise approche pour récupérer des données. Au lieu de laisser la couche de gestion décider de la meilleure manière d'extraire toutes les associations nécessaires à la couche de vue, elle force le contexte de persistance à rester ouvert afin que la couche de vue puisse déclencher l'initialisation du proxy.
- L'
OpenSessionInViewFilter
appelle la openSession
méthode du sous-jacent SessionFactory
et obtient un nouveau Session
.
- Le
Session
est lié au TransactionSynchronizationManager
.
- Les
OpenSessionInViewFilter
appels doFilter
de la javax.servlet.FilterChain
référence d'objet et la demande est ensuite traitée
- Le
DispatcherServlet
est appelé et achemine la requête HTTP vers le sous-jacent PostController
.
- L'
PostController
appel le PostService
pour obtenir une liste d' Post
entités.
- Le
PostService
ouvre une nouvelle transaction et HibernateTransactionManager
réutilise la même Session
qui a été ouverte par le OpenSessionInViewFilter
.
- Le
PostDAO
récupère la liste des Post
entités sans initialiser aucune association paresseuse.
- Le
PostService
valide la transaction sous-jacente, mais Session
n'est pas fermé car il a été ouvert en externe.
- Le
DispatcherServlet
commence le rendu de l'interface utilisateur, qui, à son tour, parcourt les associations différées et déclenche leur initialisation.
- Le
OpenSessionInViewFilter
peut fermer le Session
, et la connexion à la base de données sous-jacente est également libérée.
À première vue, cela ne semble pas être une chose terrible à faire, mais, une fois que vous l'avez vue du point de vue d'une base de données, une série de failles commencent à devenir plus évidentes.
La couche de service ouvre et ferme une transaction de base de données, mais par la suite, aucune transaction explicite n'est en cours. Pour cette raison, chaque instruction supplémentaire émise à partir de la phase de rendu de l'interface utilisateur est exécutée en mode de validation automatique. L'auto-validation met la pression sur le serveur de base de données car chaque instruction doit vider le journal des transactions sur le disque, ce qui entraîne un trafic d'E / S important côté base de données. Une optimisation serait de marquer le Connection
comme étant en lecture seule, ce qui permettrait au serveur de base de données d'éviter d'écrire dans le journal des transactions.
Il n'y a plus de séparation des préoccupations car les instructions sont générées à la fois par la couche de service et par le processus de rendu de l'interface utilisateur. L'écriture de tests d'intégration affirmant le nombre d'instructions générées nécessite de passer par toutes les couches (web, service, DAO), tout en déployant l'application sur un conteneur web. Même lors de l'utilisation d'une base de données en mémoire (par exemple HSQLDB) et d'un serveur Web léger (par exemple Jetty), ces tests d'intégration seront plus lents à exécuter que si les couches étaient séparées et que les tests d'intégration back-end utilisaient la base de données, tandis que le les tests d'intégration frontale se moquaient complètement de la couche de service.
La couche d'interface utilisateur est limitée à la navigation dans les associations qui peuvent, à leur tour, déclencher des problèmes de requête N + 1. Bien qu'Hibernate propose @BatchSize
de récupérer les associations par lots et FetchMode.SUBSELECT
de faire face à ce scénario, les annotations affectent le plan de récupération par défaut, elles sont donc appliquées à chaque cas d'utilisation métier. Pour cette raison, une requête de couche d'accès aux données est beaucoup plus appropriée car elle peut être adaptée aux exigences de récupération de données du cas d'utilisation actuel.
Enfin, la connexion à la base de données peut être maintenue tout au long de la phase de rendu de l'interface utilisateur (en fonction du mode de libération de votre connexion), ce qui augmente la durée du bail de connexion et limite le débit global des transactions en raison de la congestion du pool de connexions de la base de données. Plus la connexion est maintenue, plus d'autres requêtes simultanées vont attendre pour obtenir une connexion à partir du pool.
Donc, soit vous maintenez la connexion pendant trop longtemps, soit vous acquérez / libérez plusieurs connexions pour une seule requête HTTP, ce qui exerce une pression sur le pool de connexions sous-jacent et limite l'évolutivité.
Botte de printemps
Malheureusement, Open Session in View est activé par défaut dans Spring Boot .
Donc, assurez-vous que dans le application.properties
fichier de configuration, vous avez l'entrée suivante:
spring.jpa.open-in-view=false
Cela désactivera OSIV, afin que vous puissiez gérer LazyInitializationException
la bonne manière .