¿Cuál es esta propiedad spring.jpa.open-in-view = true en Spring Boot?

121

Vi una spring.jpa.open-in-view=truepropiedad en la documentación de Spring Boot para la configuración de JPA.

  • ¿Es el truevalor predeterminado para esta propiedad si no se proporciona en absoluto ?;
  • ¿Qué hace esto realmente? No encontré ninguna buena explicación para ello;
  • ¿Te hace usar en SessionFactorylugar de EntityManagerFactory? Si es así, ¿cómo puedo decirle que me permita usarlo EntityManagerFactoryen su lugar?

¡Gracias!

Carlos Alberto
fuente

Respuestas:

52

Esta propiedad registrará un OpenEntityManagerInViewInterceptor, que registra un EntityManageren el hilo actual, por lo que tendrá el mismo EntityManagerhasta que finalice la solicitud web. No tiene nada que ver con Hibernate, SessionFactoryetc.

Dunni
fuente
Por el momento tengo el filtro OpenEntityManagerInViewFilter para controlar el EntityManager hasta que finalice la solicitud web. ¿Este interceptor al que se refería "OpenEntityManagerInViewInterceptor" es el mismo que "OpenEntityManagerInViewFilter"? ¿Cual es la diferencia entre ellos? Entonces, ¿no tendría más este filtro en mi contexto de servlet para Spring Boot?
Carlos Alberto
1
El interceptor solo funciona cuando usa el DispatcherServlet en Spring (porque el interceptor es un mecanismo Spring). El filtro se puede asignar a todos los servlets configurados (lo usamos para FacesServlet en una de nuestras aplicaciones). Entonces, si solo usa DispatcherServlet, puede agregar la propiedad y eliminar el filtro; de lo contrario, use el filtro.
Dunni
298

El antipatrón OSIV

En lugar de dejar que la capa empresarial decida cómo es mejor obtener todas las asociaciones que necesita la capa de vista, OSIV (Sesión abierta en vista) obliga al contexto de persistencia a permanecer abierto para que la capa de vista pueda activar la inicialización del proxy, como se ilustra. por el siguiente diagrama.

ingrese la descripción de la imagen aquí

  • El OpenSessionInViewFilterllama al openSessionmétodo del subyacente SessionFactoryy obtiene un nuevo Session.
  • El Sessionestá vinculado al TransactionSynchronizationManager.
  • Las OpenSessionInViewFilterllamadas a la referencia doFilterdel javax.servlet.FilterChainobjeto y la solicitud se procesan más.
  • Se DispatcherServletllama y enruta la solicitud HTTP al subyacente PostController.
  • El PostControllerllama a PostServicepara obtener una lista de Postentidades.
  • La PostServiceabre una nueva transacción, y la HibernateTransactionManagervuelve a utilizar el mismo Sessionque fue inaugurado por el OpenSessionInViewFilter.
  • El PostDAOObtiene la lista de Postentidades sin inicializar cualquier forma de asociación perezoso.
  • El PostServiceconfirma la transacción subyacente, pero el Sessionno está cerrada, ya que se abrió el exterior.
  • El DispatcherServletcomienza a representar la interfaz de usuario, que, a su vez, navega por las asociaciones perezosas y activa su inicialización.
  • El OpenSessionInViewFilterpuede cerrar el Session, y la conexión de base de datos subyacente se libera también.

A primera vista, esto puede no parecer algo terrible, pero, una vez que lo ve desde la perspectiva de una base de datos, una serie de fallas comienzan a volverse más obvias.

La capa de servicio abre y cierra una transacción de base de datos, pero luego, no hay ninguna transacción explícita. Por esta razón, cada declaración adicional emitida desde la fase de representación de la interfaz de usuario se ejecuta en modo de confirmación automática. La confirmación automática ejerce presión sobre el servidor de la base de datos porque cada declaración debe vaciar el registro de transacciones en el disco, lo que provoca una gran cantidad de tráfico de E / S en el lado de la base de datos. Una optimización sería marcar Connectioncomo de solo lectura, lo que permitiría al servidor de la base de datos evitar escribir en el registro de transacciones.

Ya no hay separación de preocupaciones porque las declaraciones son generadas tanto por la capa de servicio como por el proceso de representación de la interfaz de usuario. Escribir pruebas de integración que afirmen la cantidad de declaraciones que se generan requiere pasar por todas las capas (web, servicio, DAO) mientras se implementa la aplicación en un contenedor web. Incluso cuando se utiliza una base de datos en memoria (por ejemplo, HSQLDB) y un servidor web ligero (por ejemplo, Jetty), estas pruebas de integración serán más lentas de ejecutar que si las capas estuvieran separadas y las pruebas de integración de back-end utilizaran la base de datos, mientras que Las pruebas de integración de front-end se burlaban de la capa de servicio por completo.

La capa de interfaz de usuario se limita a las asociaciones de navegación que, a su vez, pueden desencadenar problemas de consulta N + 1 . Aunque Hibernate ofrece la @BatchSizeposibilidad de buscar asociaciones en lotes y FetchMode.SUBSELECTpara hacer frente a este escenario, las anotaciones afectan el plan de recuperación predeterminado, por lo que se aplican a todos los casos de uso empresarial. Por esta razón, una consulta de la capa de acceso a datos es mucho más adecuada porque se puede adaptar a los requisitos de obtención de datos del caso de uso actual.

Por último, pero no menos importante, la conexión de la base de datos se mantiene durante la fase de representación de la interfaz de usuario, lo que aumenta el tiempo de concesión de la conexión y limita el rendimiento general de la transacción debido a la congestión en el grupo de conexiones de la base de datos. Cuanto más se mantenga la conexión, más otras solicitudes simultáneas esperarán para obtener una conexión del grupo.

Spring Boot y OSIV

Desafortunadamente, OSIV (Sesión abierta en vista) está habilitado de forma predeterminada en Spring Boot , y OSIV es realmente una mala idea desde una perspectiva de rendimiento y escalabilidad .

Por lo tanto, asegúrese de que en el application.propertiesarchivo de configuración tenga la siguiente entrada:

spring.jpa.open-in-view=false

Esto desactivará OSIV para que pueda manejar de la LazyInitializationExceptionmanera correcta .

A partir de la versión 2.0, Spring Boot emite una advertencia cuando OSIV está habilitado de forma predeterminada, por lo que puede descubrir este problema mucho antes de que afecte a un sistema de producción.

Para obtener más detalles sobre OSIV, consulte este artículo .

Vlad Mihalcea
fuente
14
Actualmente se está registrando una ADVERTENCIA.
Vlad Mihalcea
¿Esto se aplica a Spring en general, o solo a Spring Boot? ¿Se puede deshabilitar esto a través de una clase anotada en la configuración @ en lugar de establecer una propiedad?
Gordon
2
Solo se aplica a Spring Boot. En Spring estándar, usted elige explícitamente qué beans usar o si desea un filtro web, como OSIV. No sé si puedes desactivarlo mediante alguna anotación. Solo conozco el ajuste de configuración.
Vlad Mihalcea
No es un anti-patrón. Tiene impactos en el rendimiento, a veces negativos, muchas veces bastante neutrales y de una manera positiva en muchos casos: si realmente desea una relación perezosa para empezar, no necesita hacer la consulta en todos los casos. y puede evitarlo cuando sea necesario utilizando open-in-view.
ymajoros
5
Según Wikipedia, "un anti-patrón es una respuesta común a un problema recurrente que suele ser ineficaz y corre el riesgo de ser altamente contraproducente". Eso es exactamente lo que es Open Session in View.
Vlad Mihalcea