Sesión abierta a la vista en Spring Boot: The Phantom Menace

Todos aquí tienen razón, cada uno a su manera y, por lo tanto, todos aquí están equivocados.
"El cuento de los tres" (A. y B. Strugatsky)

Si usa Spring Data JPA, luego de actualizar a Spring Boot 2, cuando inicie la aplicación, puede notar una nueva advertencia en el registro:


spring.jpa.open-in-view está habilitado de forma predeterminada. Por lo tanto, las consultas de la base de datos se pueden realizar durante la representación de la vista. Configure explícitamente spring.jpa.open-in-view para deshabilitar esta advertencia.

En este artículo intentaré explicar qué significa, quién tiene la culpa y qué hacer.


Para generar una aplicación completa en Spring Boot, solo se @SpringBootApplication una anotación @SpringBootApplication . Para hacer esto posible, el marco utiliza una gran cantidad de configuraciones automáticas y configuraciones predeterminadas. Además, para trabajar fuera de la caja, los desarrolladores de Spring Boot tuvieron que elegir algunos conceptos de desarrollo de aplicaciones entre varias opciones alternativas para cada uno, de modo que el usuario no necesitara seleccionarlos explícitamente. Por un lado, esto es bueno para un inicio rápido y un desarrollo fácil, pero por otro lado, después de un tiempo puede resultar que algún concepto / paradigma / configuración predeterminado no sea adecuado para el proyecto, y se tendrá que hacer mucho trabajo para abandonarlo. Uno de estos conceptos es el modo Open Session In View (OSIV) , que se incluye por defecto en Spring Boot.


En este modo, la sesión de Hibernate se mantiene abierta todo el tiempo que se procesa la solicitud HTTP, incluida la etapa de creación de la Vista (recurso JSON o página HTML). Esto hace posible cargar datos de forma perezosa en la capa de presentación después de confirmar una transacción en la capa de lógica de negocios. Por ejemplo, solicitamos la entidad Article de la base de datos. El artículo debe mostrarse junto con los comentarios. OSIV le permite simplemente llamar al método de entidad getComments() al representar HTML, y los comentarios se cargarán en una solicitud por separado. Cuando el modo OSIV está desactivado, obtendremos una LazyInitializationException , porque la sesión ya está cerrada y la entidad del Article ya no es administrada por Hibernate. La mayoría de los desarrolladores de Hibernate han encontrado una LazyInitializationException ; OSIV le permite evitarlo cargando datos según sea necesario en cualquier etapa del procesamiento de la solicitud HTTP.


OSIV en Spring Boot se implementa utilizando la OpenEntityManagerInViewInterceptor solicitud web OpenEntityManagerInViewInterceptor . A diferencia de Spring puro, aquí está habilitado por defecto.


OSIV se considera antipatrón. Lo mejor de todo, el lado perjudicial de su artículo fue explicado por Vlad Mihalcea, uno de los desarrolladores de Hibernate: The Open Session In View Anti-Pattern . Puntos clave:


  • Las consultas de bases de datos sin una transacción funcionan en modo de confirmación automática, cargándolas en gran medida.
  • No hay separación de responsabilidades, cualquier capa de aplicación puede generar consultas SQL, lo que dificulta las pruebas.
  • Hay un problema n + 1 cuando cada colección relacionada con una entidad se carga en una solicitud separada.
  • Las conexiones largas a la base de datos nuevamente aumentan la carga y reducen el rendimiento.

Estos son problemas bastante desagradables del modo OSIV y, al parecer, fuertes argumentos para no usarlo. Sin embargo, en una solicitud para deshabilitarlo de manera predeterminada , los desarrolladores de Spring Boot también presentaron buenas razones por las cuales OSIV debería habilitarse para nuevos proyectos:


  • Compatibilidad con versiones anteriores. Las aplicaciones existentes al actualizar a Spring Boot 2 pueden encontrar errores y errores debido a OSIV deshabilitado. Para evitar esto, solo necesita establecer el valor único spring.jpa.open-in-view , pero esto también dificulta el cambio a la nueva versión.
  • La facilidad de uso para principiantes y un inicio rápido son importantes para Spring Boot. Si OSIV está desactivado, puede que no esté claro para los principiantes por qué algo tan intuitivamente esperado como recibir una colección de elementos relacionados al acceder a un método de entidad no funciona. En cambio, el usuario recibirá una LazyInitializationException , esto ralentizará su camino hacia una aplicación en ejecución.
  • OSIV le permite aumentar la simplicidad del código, la usabilidad y la velocidad de desarrollo.
  • Es difícil encontrar ejemplos simples de cómo se debe construir una aplicación sin OSIV.
  • Sin OSIV, la capa de lógica de negocios necesita saber cómo se presentarán los datos en la interfaz de usuario, es decir, qué DTO necesitará o qué datos relacionados deben cargarse junto con la entidad raíz. Esto es nuevamente la ausencia de una división de responsabilidad.

Entonces, podemos distinguir dos puntos de vista sobre este problema. Desde el punto de vista del arquitecto de la base de datos (DBA), Open Session In View es ciertamente inaceptable, ya que la interacción de la aplicación con la base de datos no está organizada de manera óptima y crea una mayor carga. Pero a menudo utilizamos soluciones menos óptimas para la velocidad, la facilidad de desarrollo y la facilidad de herramientas de aprendizaje: escribimos en lenguajes administrados, usamos formatos de datos de texto para la interacción de la red, etc. Desde la posición de un desarrollador de framework, para simplificar el desarrollo y el inicio rápido de los principiantes, OSIV le permite reducir la carga cognitiva, la cantidad de conceptos necesarios para comenzar a desarrollar la aplicación. Si el desarrollador eligió JPA, ya estuvo de acuerdo con una cierta degradación del rendimiento a cambio de la conveniencia del desarrollo. JPA ayuda a hacer amigos los objetos y los modelos de datos relacionales. Cuando trabajamos en el estilo de objeto para obtener elementos relacionados, simplemente recurrimos al método de entidad (incluso si está en la capa de presentación), es simple, lógico e intuitivamente esperado, aunque esta simplicidad es engañosa.


Hay muchos ejemplos y tutoriales para trabajar en la sesión abierta. En el modo Ver, la arquitectura en su conjunto es clara: la capa de servicio solicita una entidad JPA, la capa de presentación la serializa directamente en JSON, a través de un DTO intermedio, o utiliza los datos de esta para representar una página HTML.


Menos claro es cómo trabajar sin OSIV. Uno de los desarrolladores de Spring en la solicitud mencionada se queja de esto, dicen muchos gritos sobre el antipatrón, pero no hay ejemplos simples de cómo vivir sin él. En esta realización, las entidades se pueden usar solo para escribir y para leer, varios DTO, separados para cada conjunto de datos en la interfaz de usuario, que se asignan directamente desde la base de datos. O consultas SQL personalizadas que describen la unión de las colecciones relacionadas necesarias para una consulta web en particular. Es decir, más repetitivo y una descripción de las necesidades de la interfaz de usuario en la capa de lógica de negocios. Con OSIV deshabilitado, la abstracción JPA comienza a fluir, la aplicación describe más detalles técnicos de la interacción con la base de datos.


Por lo tanto, el desarrollo con OSIV es más simple. Pero el problema es que si en el futuro desea abandonarlo, tendrá que rehacer mucho, el concepto de trabajar con la base de datos en el proyecto estableciendo una propiedad no se puede cambiar. Es posible que deba rehacer toda la arquitectura de la aplicación. Sin embargo, abandonar OSIV puede ser una optimización prematura, que ralentizará la velocidad de desarrollo, que puede ser crítica para un inicio, por ejemplo. Puede usar OSIV y optimizar las consultas de la base de datos solo en los lugares más lentos. Por ejemplo, las colecciones de entidades que consultan son las que más sufren el problema n + 1, cuando cada entidad extrae varias consultas de colecciones relacionadas.


Entonces, si quieres hacerlo bien, debes desarrollar sin OSIV. Pero si la velocidad de desarrollo y la simplicidad del código son importantes, puede usar este modo, resignado a alguna pérdida de rendimiento.


Lo principal es que este problema de rendimiento no se convierte en una gran deuda técnica después de unos años. Es doblemente peligroso cuando los desarrolladores no sospechan que esta deuda se está acumulando en ellos, porque Spring Boot silenciosamente eligió el concepto de Open Session In View para ellos. Por lo tanto, es excelente que, como resultado de la solicitud mencionada anteriormente, se haya decidido mostrar en el registro una advertencia sobre el modo utilizado, que cité al comienzo del artículo.


Espero que la advertencia y este artículo sobre él ayuden a los desarrolladores a tomar una decisión más informada: usar el concepto de Open Session In View en una aplicación en Spring Boot. He citado y discutido los principales argumentos a favor y en contra, y también aconsejo leer la discusión original. Este problema muestra que una gran cantidad de configuraciones automáticas y valores predeterminados en Spring / Spring Boot pueden ser peligrosos para los desarrolladores desatentos.


¿Utiliza OSIV en las aplicaciones Spring Boot? Si no, ¿cómo está organizada la arquitectura para la interacción de la capa de presentación con la base de datos? ¿Qué técnicas y / o bibliotecas se utilizan para esto?

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


All Articles