Para obtener una descripción más detallada, puede leer mi Antipatrón en vista de sesión abierta . De lo contrario, aquí hay un resumen de por qué no debería usar Open Session In View.
Open Session In View adopta un enfoque inadecuado para la obtención de datos. En lugar de dejar que la capa empresarial decida cómo es mejor obtener todas las asociaciones que necesita la capa de vista, obliga al contexto de persistencia a permanecer abierto para que la capa de vista pueda activar la inicialización del proxy.
- El
OpenSessionInViewFilter
llama al openSession
método del subyacente SessionFactory
y obtiene un nuevoSession
.
- El
Session
está ligado alTransactionSynchronizationManager
.
- Las
OpenSessionInViewFilter
llamadas doFilter
de lajavax.servlet.FilterChain
referencia objeto y la solicitud se procesan más.
- Se
DispatcherServlet
llama y enruta la solicitud HTTP al subyacentePostController
.
- El
PostController
llama a PostService
para obtener una lista de Post
entidades.
- La
PostService
abre una nueva transacción, y la HibernateTransactionManager
vuelve a utilizar el mismo Session
que fue inaugurado por el OpenSessionInViewFilter
.
- El
PostDAO
Obtiene la lista de Post
entidades sin inicializar cualquier forma de asociación perezoso.
- El
PostService
confirma la transacción subyacente, pero elSession
no está cerrada, ya que se abrió el exterior.
- los
DispatcherServlet
aperturas de representación de la interfaz de usuario, lo que, a su vez, navega por las asociaciones perezosos y desencadena su inicialización.
- El
OpenSessionInViewFilter
puede 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 Connection
como 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 @BatchSize
posibilidad de obtener asociaciones en lotes y FetchMode.SUBSELECT
para hacer frente a este escenario, las anotaciones están afectando el plan de recuperación predeterminado, por lo que se aplican a cada caso 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 podría mantenerse durante la fase de representación de la interfaz de usuario (según el modo de liberación de la conexión), lo que aumenta el tiempo de concesión de la conexión y limita el rendimiento general de las transacciones 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 solicitudes simultáneas esperarán para obtener una conexión del grupo.
Entonces, o mantiene la conexión durante demasiado tiempo, o adquiere / libera múltiples conexiones para una sola solicitud HTTP, lo que ejerce presión sobre el grupo de conexiones subyacentes y limita la escalabilidad.
Bota de primavera
Desafortunadamente, Open Session in View está habilitado de forma predeterminada en Spring Boot .
Por lo tanto, asegúrese de que en el application.properties
archivo de configuración tenga la siguiente entrada:
spring.jpa.open-in-view=false
Esto desactivará OSIV, para que pueda manejar de la LazyInitializationException
manera correcta .