Session ouverte en vue dans Spring Boot: The Phantom Menace

Tout le monde ici a raison, chacun à sa manière, et donc tout le monde ici a tort.
"Le conte des trois" (A. et B. Strugatsky)

Si vous utilisez Spring Data JPA, puis après la mise à niveau vers Spring Boot 2, lorsque vous démarrez l'application, vous pouvez remarquer un nouvel avertissement dans le journal:


spring.jpa.open-in-view est activé par défaut. Par conséquent, des requêtes de base de données peuvent être effectuées pendant le rendu de la vue. Configurez explicitement spring.jpa.open-in-view pour désactiver cet avertissement.

Dans cet article, j'essaierai d'expliquer ce que cela signifie, qui est à blâmer et que faire.


Pour générer une application à part entière sur Spring Boot, une @SpringBootApplication annotation @SpringBootApplication est @SpringBootApplication . Pour rendre cela possible, le framework utilise un grand nombre de configurations automatiques et de paramètres par défaut. De plus, pour fonctionner dès le départ, les développeurs de Spring Boot ont dû choisir certains concepts de développement d'applications parmi plusieurs options alternatives pour chacun, afin que l'utilisateur n'ait pas besoin de les sélectionner explicitement. D'une part, c'est bon pour un démarrage rapide et un développement facile, mais d'autre part, après un certain temps, il peut s'avérer qu'un concept / paradigme / paramètre par défaut ne convient pas au projet, et beaucoup de travail devra être fait pour l'abandonner. Un tel concept est le mode Open Session In View (OSIV) , qui est inclus par défaut dans Spring Boot.


Dans ce mode, la session Hibernate est maintenue ouverte tout le temps que la requête HTTP est traitée, y compris l'étape de création de la vue (ressource JSON ou page HTML). Cela permet de charger paresseusement des données dans la couche présentation après avoir validé une transaction dans la couche logique métier. Par exemple, nous demandons l'entité Article à la base de données. L'article doit être affiché avec des commentaires. OSIV vous permet d'appeler simplement la méthode d'entité getComments() lors du rendu HTML, et les commentaires seront chargés dans une demande distincte. Lorsque le mode OSIV est désactivé, nous obtiendrons une LazyInitializationException , car la session est déjà fermée et l'entité Article n'est plus gérée par Hibernate. La plupart des développeurs Hibernate ont rencontré une LazyInitializationException ; OSIV vous permet de l'éviter en chargeant les données nécessaires à n'importe quelle étape du traitement de la requête HTTP.


OSIV dans Spring Boot est implémenté à l'aide de la OpenEntityManagerInViewInterceptor demande Web OpenEntityManagerInViewInterceptor . Contrairement à Pure Spring, ici, il est activé par défaut.


OSIV est considéré comme anti-modèle. Mieux encore, le côté nocif de son article a été expliqué par Vlad Mihalcea, l'un des développeurs d'Hibernate: The Open Session In View Anti-Pattern . Points clés:


  • Les requêtes de base de données sans transaction fonctionnent en mode de validation automatique, en la chargeant fortement.
  • Il n'y a pas de séparation des responsabilités, n'importe quelle couche d'application peut générer des requêtes SQL, ce qui rend les tests difficiles.
  • Il existe un problème n + 1 lorsque chaque collection liée à une entité est chargée dans une demande distincte.
  • De longues connexions à la base de données augmentent à nouveau la charge et réduisent le débit.

Ce sont des problèmes assez désagréables du mode OSIV et, semble-t-il, de solides arguments pour ne pas l'utiliser. Cependant, dans une demande de désactivation par défaut , les développeurs de Spring Boot ont également expliqué pourquoi OSIV devrait être activé pour les nouveaux projets:


  • Compatibilité descendante. Les applications existantes lors de la mise à niveau vers Spring Boot 2 peuvent rencontrer des erreurs et des bogues en raison de l'OSIV désactivé. Pour éviter cela, il vous suffit de définir la valeur unique spring.jpa.open-in-view , mais cela rend également difficile le passage à la nouvelle version.
  • La facilité d'utilisation pour les débutants et un démarrage rapide sont importants pour Spring Boot. Si vous désactivez OSIV, il peut ne pas être clair pour les débutants pourquoi une chose aussi intuitive que d'obtenir une collection d'éléments liés lors de l'accès à une méthode d'entité ne fonctionne pas. Au lieu de cela, l'utilisateur recevra une LazyInitializationException , ce qui ralentira son chemin vers une application en cours d'exécution.
  • OSIV vous permet d'augmenter la simplicité, la convivialité et la vitesse de développement du code.
  • Il est difficile de trouver des exemples simples de la façon dont une application doit être construite sans OSIV.
  • Sans OSIV, la couche logique métier doit savoir comment les données seront présentées dans l'interface utilisateur, c'est-à-dire de quel DTO elle aura besoin ou quelles données connexes devraient être chargées avec l'entité racine. C'est là encore l'absence de partage des responsabilités.

Ainsi, nous pouvons distinguer deux vues sur ce problème. Du point de vue de l'architecte de base de données (DBA), Open Session In View est certainement inacceptable, car l'interaction de l'application avec la base de données n'est pas organisée de manière optimale et génère une charge accrue. Mais nous utilisons souvent des solutions moins optimales pour la vitesse, la facilité de développement et la facilité des outils d'apprentissage - nous écrivons dans des langages gérés, nous utilisons des formats de données texte pour l'interaction réseau, etc. De la position d'un développeur de framework, pour simplifier le développement et le démarrage rapide des débutants, OSIV vous permet de réduire la charge cognitive, le nombre de concepts nécessaires pour commencer à développer l'application. Si le développeur a choisi JPA, il a déjà accepté une certaine dégradation des performances en échange de la commodité du développement. JPA permet de se faire des amis des modèles de données objet et relationnels. Lorsque nous travaillons dans le style d'objet pour obtenir des éléments liés, nous nous tournons simplement vers la méthode d'entité (même si dans la couche de présentation), elle est simple, logique et intuitive, bien que cette simplicité soit trompeuse.


Il existe de nombreux exemples et tutoriels pour travailler en session ouverte En mode Affichage, l'architecture dans son ensemble est claire: la couche de service demande une entité JPA, la couche de présentation la sérialise directement en JSON, via un DTO intermédiaire, ou utilise les données de celle-ci pour rendre une page HTML.


La façon de travailler sans OSIV est moins claire. L'un des développeurs de Spring dans la demande mentionnée s'en plaint, ils disent beaucoup de cris au sujet de l'anti-modèle, mais il n'y a pas d'exemples simples de comment vivre sans. Dans ce mode de réalisation, les entités peuvent être utilisées uniquement pour écrire et pour lire plusieurs DTO, séparés pour chaque ensemble de données dans l'interface utilisateur, qui sont mappés directement à partir de la base de données. Ou des requêtes SQL personnalisées décrivant la jointure des collections associées nécessaires pour une requête Web particulière. C'est-à-dire, plus de détails et une description des besoins de l'interface utilisateur dans la couche de logique métier. Avec OSIV désactivé, l'abstraction JPA commence à couler, l'application décrit des détails plus techniques de l'interaction avec la base de données.


Ainsi, le développement avec OSIV est plus simple. Mais le problème est que si à l'avenir vous voulez l'abandonner, vous devrez refaire beaucoup, le concept de travailler avec la base de données dans le projet en définissant une propriété ne peut pas être changé. Vous devrez peut-être refaire toute l'architecture de l'application. Cependant, l'abandon de OSIV peut être une optimisation prématurée, ce qui ralentira la vitesse de développement, ce qui peut être critique pour un démarrage, par exemple. Vous pouvez utiliser OSIV et optimiser les requêtes de base de données uniquement dans les endroits les plus lents. Par exemple, l'interrogation des collections d'entités souffre le plus du problème n + 1, lorsque chaque entité extrait plusieurs requêtes des collections associées.


Donc, si vous voulez le faire correctement, vous devez développer sans OSIV. Mais si la vitesse de développement et la simplicité du code sont importantes, vous pouvez utiliser ce mode, résigné à une certaine perte de performances.


L'essentiel est que ce problème de performance ne se transforme pas en une énorme dette technique après quelques années. C'est doublement dangereux lorsque les développeurs ne soupçonnent pas que cette dette s'accumule en eux, car Spring Boot a choisi en silence le concept d'Open Session In View pour eux. Par conséquent, il est excellent qu'à la suite de la demande susmentionnée, il ait été décidé d'afficher dans le journal un avertissement sur le mode utilisé, que j'ai cité au début de l'article.


J'espère que l'avertissement et cet article à son sujet aideront les développeurs à prendre une décision plus éclairée - s'il faut utiliser le concept d'Open Session In View dans une application sur Spring Boot. J'ai cité et discuté les principaux arguments pour et contre, et je conseille également de lire la discussion originale. Ce problème montre qu'un grand nombre de configurations automatiques et de valeurs par défaut dans Spring / Spring Boot peut être dangereux pour les développeurs inattentifs.


Utilisez-vous OSIV dans les applications Spring Boot? Sinon, comment est organisée l'architecture d'interaction de la couche de présentation avec la base de données? Quelles techniques et / ou bibliothèques sont utilisées pour cela?

Source: https://habr.com/ru/post/fr440734/


All Articles