2009-10-08 9 views
35

Aunque se escribieron 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 típica de aplicaciones web en capas usando una capa de servicio @Transactional, el filtro funciona de la siguiente manera:Por qué no utilizar Spring's OpenEntityManagerInViewFilter

  1. El filtro intercepta una petición de servlet
  2. El filtro se abre un EntityManager y se une a el subproceso actual
  3. controlador
  4. web se llama
  5. controlador web llama a servicio
  6. transacción interceptor comienza una nueva transacción, recupera la EntityManager hilo de ruedas y se une a la transacción
  7. servicio se llama, hace algunas cosas con EntityManager, a continuación, vuelve
  8. interceptor Transacción vacía el EntityManager a continuación, confirma la transacción
  9. controlador Web prepara vista, a continuación, vuelve
  10. View está ubicado
  11. 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:

  1. Cargando varias asociaciones perezosas resultará en múltiples transacciones de bases de datos, un posible golpe en el rendimiento
  2. El objeto raíz y sus asociaciones perezosas se cargan en diferentes transacciones de bases de datos, por lo que los datos pueden ser obsoletos (por ejemplo, raíz cargada por subproceso 1, asociaciones de raíz actualizadas por subproceso 2, asociaciones de raíz cargadas por 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é opinas?

Gracias!

Respuesta

9

Como dijiste, el filtro OpenSessionInView es muy conveniente en aplicaciones web. Respecto a las limitaciones que mencionó:

1) Cargar varias asociaciones diferidas dará lugar a múltiples transacciones en la base de datos, un posible golpe en el rendimiento.

Sí, ir a la base de datos a menudo puede provocar 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 perezosos se cargan en diferentes operaciones de base de datos, por lo que los datos pueden ser posiblemente rancio (por ejemplo, raíz cargado por hilo 1, las asociaciones de raíz actualizados por hilo 2, las asociaciones de raíz cargado por hilo 1)

imaginar escribir esta aplicación en JDBC - si los requisitos de consistencia de la aplicación exigen que la raíz y las hojas ambos deben ser cargados en el mismo TXN, el uso recuperación por unión. 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 se reutilice en un contexto no web. Según su descripción, parece que no tiene ese problema.

4

El principal argumento que escuché en contra de 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.

4

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.

1

Si su aplicación es una arquitectura multicapa (la capa de vista 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.

Cuestiones relacionadas