¿Por qué se considera una mala práctica Hibernate Open Session in View?

Resuelto HeDinges asked hace 15 años • 0 respuestas

¿Y qué tipo de estrategias alternativas utiliza para evitar LazyLoadExceptions?

Entiendo que la sesión abierta a la vista tiene problemas con:

  • Aplicaciones en capas que se ejecutan en diferentes jvm
  • Las transacciones se confirman sólo al final y lo más probable es que le gusten los resultados antes.

Pero, si sabe que su aplicación se ejecuta en una única máquina virtual, ¿por qué no aliviar su dolor utilizando una estrategia de sesión abierta a la vista?

HeDinges avatar Jul 09 '09 18:07 HeDinges
Aceptado

Open Session In View adopta un mal enfoque para recuperar datos. En lugar de permitir que la capa empresarial decida cuál es la mejor manera de obtener todas las asociaciones que necesita la capa Vista, obliga al Contexto de persistencia a permanecer abierto para que la capa Vista pueda activar la inicialización del Proxy.

ingrese la descripción de la imagen aquí

  • Llama OpenSessionInViewFilteral openSessionmétodo del subyacente SessionFactoryy obtiene un nuevo Session.
  • El Sessionestá vinculado al TransactionSynchronizationManager.
  • Las OpenSessionInViewFilterllamadas a doFilterla javax.servlet.FilterChainreferencia del objeto y la solicitud se procesan aún más.
  • Se DispatcherServletllama y enruta la solicitud HTTP al archivo PostController.
  • PostControllerLlama al para PostServiceobtener una lista de Postentidades.
  • Abre PostServiceuna nueva transacción y reutiliza HibernateTransactionManagerla misma Sessionque abrió el OpenSessionInViewFilter.
  • Obtiene PostDAOla lista de Postentidades sin inicializar ninguna asociación diferida.
  • Confirma PostServicela transacción subyacente, pero Sessionno se cierra porque se abrió externamente.
  • Comienza DispatcherServleta renderizar la interfaz de usuario, que, a su vez, navega por las asociaciones diferidas y activa su inicialización.
  • Puede OpenSessionInViewFiltercerrar el archivo Sessiony la conexión de la base de datos subyacente también se libera.

A primera vista, esto puede no parecer algo terrible, pero, una vez que lo miras 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 se realiza ninguna transacción explícita. Por este motivo, 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 el archivo 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 las genera tanto la capa de servicio como 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 liviano (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 usaran la base de datos, mientras que las Las pruebas de integración front-end se burlaban por completo de la capa de servicio.

La capa de interfaz de usuario se limita a navegar por asociaciones que, a su vez, pueden desencadenar problemas de consulta N+1. Aunque Hibernate ofrece @BatchSizela posibilidad de recuperar asociaciones en lotes y FetchMode.SUBSELECThacer 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 este motivo, una consulta de capa de acceso a datos es mucho más adecuada porque puede adaptarse 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 toda la fase de representación de la interfaz de usuario (dependiendo del modo de liberación de su conexión), 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 solicitudes simultáneas esperarán para obtener una conexión del grupo.

Por lo tanto, 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 subyacente y limita la escalabilidad.

Bota de primavera

Desafortunadamente, Abrir sesión en vista está habilitado de forma predeterminada en Spring Boot .

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

spring.jpa.open-in-view=false

Esto deshabilitará OSIV, para que pueda manejarlo de LazyInitializationExceptionla manera correcta, obteniendo todas las asociaciones necesarias mientras está EntityManagerabierto.

Vlad Mihalcea avatar May 30 '2016 13:05 Vlad Mihalcea

Porque enviar Proxies posiblemente no inicializados, especialmente colecciones, en la capa de vista y activar la carga de hibernación desde allí puede ser problemático tanto desde el punto de vista del rendimiento como de la comprensión.

Comprensión :

El uso de OSIV "contamina" la capa de visualización con preocupaciones relacionadas con la capa de acceso a datos.

La capa de vista no está preparada para manejar lo HibernateExceptionque puede ocurrir durante la carga diferida, pero presumiblemente la capa de acceso a datos sí lo está.

Actuación :

OSIV tiende a arrastrar la carga de entidades adecuada debajo de la alfombra; tiende a no darse cuenta de que sus colecciones o entidades se inicializan de manera perezosa (quizás N+1). Más comodidad, menos control.


Actualización: consulte El antipatrón OpenSessionInView para obtener una discusión más amplia sobre este tema. El autor enumera tres puntos importantes:

  1. cada inicialización diferida le proporcionará una consulta, lo que significa que cada entidad necesitará N + 1 consultas, donde N es el número de asociaciones diferidas. Si su pantalla presenta datos tabulares, leer el registro de Hibernate es un gran indicio de que no está haciendo lo que debería.
  2. esto anula completamente la arquitectura en capas, ya que te mancha las uñas con DB en la capa de presentación. Esta es una estafa conceptual, así que podría vivir con ella, pero hay un corolario.
  3. Por último, pero no menos importante, si ocurre una excepción al recuperar la sesión, ocurrirá durante la escritura de la página: no puede presentar una página de error limpia al usuario y lo único que puede hacer es escribir un mensaje de error en el cuerpo.
Robert Munteanu avatar Jul 09 '2009 11:07 Robert Munteanu
  • las transacciones se pueden confirmar en la capa de servicio; las transacciones no están relacionadas con OSIV. Es lo Sessionque permanece abierto, no una transacción, en ejecución.

  • Si las capas de su aplicación están distribuidas en varias máquinas, entonces prácticamente no puede usar OSIV: debe inicializar todo lo que necesita antes de enviar el objeto por cable.

  • OSIV es una forma agradable y transparente (es decir, ninguno de su código se da cuenta de que esto sucede) de aprovechar los beneficios de rendimiento de la carga diferida.

Bozho avatar Sep 21 '2010 12:09 Bozho

No diría que Open Session In View se considere una mala práctica; ¿Qué te da esa impresión?

Open-Session-In-View es un enfoque simple para manejar sesiones con Hibernate. Porque es simple, a veces es simplista. Si necesita un control detallado sobre sus transacciones, como tener múltiples transacciones en una solicitud, Open-Session-In-View no siempre es un buen enfoque.

Como otros han señalado, OSIV tiene algunas ventajas y desventajas: eres mucho más propenso al problema N+1 porque es menos probable que te des cuenta de qué transacciones estás iniciando. Al mismo tiempo, significa que no necesita cambiar su capa de servicio para adaptarse a cambios menores en su vista.

Geoffrey Wiseman avatar Jul 21 '2009 15:07 Geoffrey Wiseman