not lazyinitializationexception initialize could java hibernate jpa lazy-loading open-session-in-view

java - lazyinitializationexception - ¿Por qué Hibernate Open Session in View es considerada una mala práctica?



could not initialize proxy no session jpa (9)

Acabo de hacer una publicación sobre algunas pautas sobre cuándo usar la sesión abierta a la vista en mi blog. Compruébalo si estás interesado.

http://heapdump.wordpress.com/2010/04/04/should-i-use-open-session-in-view/

¿Y qué tipo de estrategias alternativas usas 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 comprometen solo al final, y lo más probable es que desee los resultados antes.

Pero, si sabe que su aplicación se ejecuta en una sola vm, ¿por qué no aliviar su dolor utilizando una estrategia de sesión abierta a la vista?


Debido a que el envío de Proxies posiblemente no inicializados, especialmente colecciones, en la capa de visualización y la activación de la carga de hibernación desde allí puede ser problemático tanto desde el punto de vista del rendimiento como del entendimiento.

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 una HibernateException que puede ocurrir cuando se carga de forma diferida, pero presumiblemente la capa de acceso a datos sí lo está.

Rendimiento :

OSIV tiende a tirar de la carga de la entidad apropiada debajo de la alfombra: usted tiende a no darse cuenta de que sus colecciones o entidades se inicializan con pereza (tal vez N + 1). Más conveniencia, menos control.

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

  1. cada inicialización lenta le generará 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 una gran pista de que usted no hace lo que debería.
  2. esto derrota por completo la arquitectura estratificada, ya que manchas tus uñas con DB en la capa de presentación. Esto es una estafa conceptual, así que podría vivir con eso, pero hay un corolario
  3. Por último, pero no menos importante, si se produce una excepción al recuperar la sesión, se producirá durante la escritura de la página: no se puede presentar una página de error de limpieza al usuario y lo único que se puede hacer es escribir un mensaje de error en el cuerpo

En mi propia experiencia, OSIV no es tan malo. El único arreglo que hice fue usar dos transacciones diferentes: - la primera, abierta en "capa de servicio", donde tengo la "lógica de negocios" - la segunda abierta justo antes de la representación de la vista


Esto no servirá de mucho, pero puedes consultar mi tema aquí: * Hibernate Cache1 OutOfMemory con OpenSessionInView

Tengo algunos problemas con OutOfMemory debido a OpenSessionInView y muchas entidades cargadas, porque permanecen en el nivel 1 de la memoria caché de Hibernate y no son basura (cargo muchas entidades con 500 elementos por página, pero todas las entidades permanecen en caché)


Estoy v. Oxidado en Hibernate ... pero creo que es posible tener múltiples transacciones en una sesión de Hibernate. Por lo tanto, los límites de su transacción no tienen que ser los mismos que los eventos de inicio / detención de la sesión.

OSIV, imo, principalmente es útil porque podemos evitar escribir código para iniciar un ''contexto de persistencia'' (también conocido como sesión) cada vez que la solicitud necesita hacer un acceso a DB.

En la capa de servicio, es probable que deba realizar llamadas a métodos que tienen diferentes necesidades de transacción, como ''Requerido, Nuevo requerido, etc.'' Lo único que necesitan estos métodos es que alguien (es decir, el filtro OSIV) haya iniciado el contexto de persistencia, de modo que solo tengan que preocuparse por: "oye dame la sesión de hibernación para este hilo ... necesito hacer algo Cosas de DB ".


No diría que Open Session In View se considera 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 minucioso de sus transacciones, como tener múltiples transacciones en una solicitud, Open-Session-In-View no siempre es un buen enfoque.

Como han señalado otros, hay algunas compensaciones para OSIV: usted es mucho más propenso al problema de N + 1 porque es menos probable que se dé cuenta de las transacciones que está iniciando. Al mismo tiempo, significa que no necesita cambiar su capa de servicio para adaptarse a cambios menores en su vista.


Para una descripción más larga, puede leer mi artículo Open Session In View Anti-Pattern . De lo contrario, aquí hay un resumen de por qué no debería usar Open Session In View.

Abrir sesión en vista tiene un mal enfoque para obtener datos. En lugar de dejar que la capa empresarial decida cómo es mejor obtener todas las asociaciones que necesita la capa Vista, obliga al Contexto de persistencia a permanecer abierto para que la capa de Vista pueda desencadenar la inicialización del Proxy.

  • OpenSessionInViewFilter llama al método openSession de la SessionFactory subyacente y obtiene una nueva Session .
  • La Session está vinculada al TransactionSynchronizationManager .
  • OpenSessionInViewFilter llama al doFilter de la referencia de objeto javax.servlet.FilterChain y la solicitud se procesa adicionalmente
  • Se llama al DispatcherServlet y enruta la solicitud HTTP al PostController subyacente.
  • El PostController llama al PostService para obtener una lista de entidades Post .
  • El PostService abre una nueva transacción y el HibernateTransactionManager reutiliza la misma Session que fue abierta por OpenSessionInViewFilter .
  • PostDAO obtiene la lista de entidades Post sin inicializar ninguna asociación diferida.
  • PostService confirma la transacción subyacente, pero la Session no se cierra porque se abrió externamente.
  • El DispatcherServlet comienza a renderizar la UI, que, a su vez, navega por las asociaciones diferidas y desencadena su inicialización.
  • OpenSessionInViewFilter puede cerrar la Session y también se libera la conexión de base de datos subyacente.

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

La capa de servicio abre y cierra una transacción de base de datos, pero después, no hay ninguna transacción explícita en curso. Por esta razón, cada instrucción adicional emitida desde la fase de renderización de la interfaz de usuario se ejecuta en el modo de confirmación automática. El autocompromiso ejerce presión sobre el servidor de la base de datos porque cada enunciado debe vaciar el registro de transacciones en el disco, lo que provoca un gran tráfico de E / S en el lado de la base de datos. Una optimización sería marcar la Connection como de solo lectura, lo que permitiría que el servidor de la base de datos evite 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 UI. Escribir pruebas de integración que afirman que 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 (p. Ej. HSQLDB) y un servidor web liviano (p. Ej. Jetty), estas pruebas de integración van a ser más lentas de ejecutar que si las capas se separaran y las pruebas de integración back-end usaran la base de datos. las pruebas de integración front-end se burlaban de la capa de servicio por completo.

La capa de IU está limitada a asociaciones de navegación que, a su vez, pueden desencadenar problemas de consulta N + 1. Aunque Hibernate ofrece @BatchSize para buscar asociaciones en lotes, y FetchMode.SUBSELECT para hacer frente a este escenario, las anotaciones están afectando al plan de recuperación predeterminado, por lo que se aplican a cada caso de uso comercial. Por esta razón, una consulta de capa de acceso a datos es mucho más adecuada porque se puede adaptar a los requisitos de búsqueda de datos de casos de uso actuales.

Por último, la conexión de la base de datos podría mantenerse durante la fase de renderización de la interfaz de usuario (dependiendo del modo de liberación de la conexión), lo que aumenta el tiempo de 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. Mientras más se mantenga la conexión, más solicitudes simultáneas esperarán para obtener una conexión del grupo.

Por lo tanto, si obtiene la conexión por demasiado tiempo, o adquiere / libera múltiples conexiones para una sola solicitud HTTP, por lo tanto, ejerce presión sobre el conjunto de conexiones subyacente y limita la escalabilidad.

Arranque de primavera

Desafortunadamente, Open Session in View está habilitada de forma predeterminada en Spring Boot .

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

spring.jpa.open-in-view=false

Esto deshabilitará OSIV, para que pueda manejar la LazyInitializationException la manera correcta .


Si está utilizando un contenedor de Inversión de control (IoC) como Spring, le recomendamos que lea sobre el alcance del frijol . Básicamente, le estoy diciendo a Spring que me dé un objeto Hibernate Session cuyo ciclo de vida abarca toda la solicitud (es decir, se crea y destruye al inicio y al final de la solicitud HTTP). No tengo que preocuparme por LazyLoadException ni cerrar la sesión ya que el contenedor IoC lo gestiona por mí.

Como se mencionó, tendrá que pensar en N + 1 SELECCIONAR problemas de rendimiento. Siempre puede configurar su entidad Hibernate para hacer una carga de unión con ganas en lugares donde el rendimiento es un problema.

La solución de alcance de frijol no es específica de un resorte. Sé que PicoContainer ofrece la misma capacidad y estoy seguro de que otros contenedores maduros de IoC ofrecen algo similar.


  • las transacciones pueden comprometerse en la capa de servicio; las transacciones no están relacionadas con OSIV. Es la Session que permanece abierta, no una transacción, ejecutándose.

  • 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 el cable.

  • OSIV es una forma agradable y transparente (es decir, ninguno de tu código es consciente de que suceda) de aprovechar los beneficios de rendimiento de la carga diferida