manytoone - lazy vs eager loading in hibernate
¿Por qué no usar Spring''s OpenEntityManagerInViewFilter? (4)
Como dijo, el filtro OpenSessionInView es muy conveniente en aplicaciones web. En cuanto a las limitaciones que mencionaste:
1) La carga de varias asociaciones perezosas generará múltiples transacciones en la base de datos, un posible impacto en el rendimiento.
Sí, ir a la base de datos a menudo puede conducir a problemas de rendimiento. Lo ideal es que busque todos los datos que necesita en un solo viaje. Considere usar Hibernate join-fetch para esto. Pero recuperar demasiados datos del DB también será lento. La regla empírica que uso es utilizar la recuperación de unir si los datos se necesitan cada vez que pinto la vista; si la información no es necesaria en la mayoría de los casos, dejo que Hibernate la busque cuando la necesite, entonces la sesión abierta threadlocal ayuda.
2) El objeto raíz y sus asociaciones perezosas se cargan en diferentes transacciones de base de datos, por lo que los datos pueden estar obsoletos (por ejemplo, raíz cargada por el hilo 1, asociaciones de raíz actualizadas por el hilo 2, asociaciones de raíz cargadas por el hilo 1).
Imagínese escribiendo esta aplicación en JDBC: si los requisitos de coherencia de la aplicación exigen que la raíz y las hojas se carguen en el mismo txn, utilice la recuperación conjunta. Si no, que a menudo es el caso, la recuperación perezosa no conducirá a ningún problema de consistencia.
En mi humilde opinión, la desventaja más importante con OpenSessionInView es cuando desea que su capa de servicio sea reutilizada en un contexto no web. Según su descripción, parece que no tiene ese problema.
Si bien se han escrito muchas publicaciones sobre el tema de OpenSession / EntityManagerInViewFilter de Spring, no pude encontrar ninguna que mencionara sus fallas. Por lo que entiendo, y asumiendo una arquitectura de aplicación web en capas típica usando una capa de servicio @Transactional, el filtro funciona de la siguiente manera:
- El filtro intercepta una solicitud de servlet
- El filtro abre un EntityManager y lo vincula al hilo actual
- Se llama controlador web
- Servicio de llamadas del controlador web
- El interceptor de transacción comienza una nueva transacción, recupera el EntityManager enlazado y lo vincula a la transacción
- Se llama al servicio, hace algunas cosas con EntityManager y luego regresa
- El interceptor de transacción vacía el EntityManager y luego confirma la transacción
- El controlador web prepara la vista y luego regresa
- La vista está construida
- El filtro cierra el EntityManager y lo desvincula del hilo actual
En los pasos 8 y 9, los objetos cargados por el EntityManager del subproceso se siguen administrando. En consecuencia, si las asociaciones diferidas se tocan en estos pasos, se cargarán de la base de datos utilizando el EntityManager aún abierto. Por lo que entiendo, cada acceso requerirá que la base de datos abra una transacción. La administración de transacciones de Spring no lo tendrá en cuenta, de ahí que lo llame "transacción implícita".
Veo 2 problemas con esto:
- Cargar varias asociaciones diferidas dará lugar a múltiples transacciones de base de datos, un posible golpe en el rendimiento
- El objeto raíz y sus asociaciones perezosas se cargan en diferentes transacciones de base de datos, por lo que los datos pueden ser obsoletos (por ejemplo, la raíz cargada por el subproceso 1, las asociaciones de raíz actualizadas por el subproceso 2, las asociaciones de raíz cargadas por el subproceso 1)
Por un lado, estos 2 problemas parecen suficientes para rechazar el uso de este filtro (impacto de rendimiento, inconsistencia de datos). Por otro lado, esta solución es muy conveniente, evita escribir varias líneas de código, el problema 1 puede no ser tan notable y el problema 2 puede ser pura paranoia.
¿Qué piensas?
¡Gracias!
El principal argumento que escuché sobre OpenSessionInView y la carga diferida es un exceso de transacciones y un impacto negativo en el rendimiento. Es extremadamente conveniente usarlo en una aplicación con pocos requisitos de uso, pero en una aplicación de gran escala, recomiendo usar los DTO (Objetos de transferencia de datos) totalmente llenos y llenos de antigüedad.
Si su aplicación es una arquitectura multicapa (la capa de visualización implementada en diferentes JVM y la capa de servicio se implementará en diferentes máquinas virtuales), entonces mantener la sesión en estado abierto no tiene sentido. Yo no vería usar OpenSessionViewFilter si su capa de servicio es independiente de su capa de aplicación.
Uno de los principales problemas que he encontrado con OpenSessionInViewFilter es el uso de aplicaciones AJAX y JavaScript. Si está utilizando javascript para representar cuadrículas o ciertos componentes de la interfaz de usuario; hay una carga lenta (considerando que enciendes el filtro); y se lanza una excepción. El procesamiento de la IU de la aplicación va por un lanzamiento. Es posible que los datos nunca aparezcan, la página comienza a lanzar extrañas excepciones de JavaScript, para lo cual debe escribir código js adicional para manejar. Y está exponiendo las excepciones de DB a los usuarios (no es una buena idea).
En una aplicación normal, estas excepciones se pueden capturar y se puede lanzar una excepción de usuario válida.