2012-05-19 14 views
11

Estoy usando Hibernate con Spring en Tomcat. He estado leyendo y volviendo a leer el tema señalado como JBoss wiki page sobre el tema, y ​​eso ha sido útil. Pero me deja algunas preguntas.Hibernate Sesión abierta en vista: ¿transacción por solicitud?

  1. La idea de iniciar una transacción para cada solicitud me preocupa. Creo que podría limitar el filtro a ciertos controladores, tal vez poner todos mis controladores que necesiten una transacción bajo una ruta pseudo "tx" o algo así. ¿Pero no es una mala idea usar transacciones si no sabes si vas a necesitar una? Y si solo estoy haciendo lecturas en alguna solicitud, dice que muy probablemente provenga de un caché, ¿no estoy mejor sin una transacción?

  2. He leído publicaciones que mencionan cómo manejaron las transacciones en la capa de servicio, y me gustaría hacer esto con Spring. Pero entonces, ¿cómo se ve el código de filtro? Todavía quiero que la sesión esté disponible en mi vista para una carga diferida.

  3. Si todo lo que tengo que hacer es llamar al sessionFactory.getCurrentSession() en mi filtro, ¿cómo se "libera" de nuevo a la fábrica de sesiones para su reutilización? (Esperaba ver un session.close() o algo así, incluso cuando usaba transacciones). ¿Quién le está diciendo a la fábrica de sesiones que esa sesión puede reutilizarse?

  4. ¿Quizás es la llamada beginTransaction() que vincula una conexión de base de datos dada a una sesión dada durante la duración de una solicitud? De lo contrario, una sesión extrae las conexiones de DB de la agrupación según sea necesario, ¿verdad?

Gracias por su paciencia con todas mis preguntas.

(Y si tu respuesta va a ser un enlace a la documentación de Spring, me harás llorar. No quieres eso, ¿verdad? Pagaré dinero real si la gente deja de responder a Spring preguntas relacionadas de esa manera.)

Respuesta

20

Sus preocupaciones son válidas, la solución proporcionada en la página wiki es demasiado simplista. La transacción no se debe gestionar en la capa web; se debe gestionar en la capa de servicio.

La implementación correcta abriría una sesión y la vincularía a un subproceso en el filtro. Ninguna transacción se inicia. La sesión se pone nunca en modo de lavado: modo de solo lectura. Una llamada de servicio establecería la sesión al modo de descarga automática & iniciar/confirmar la transacción. Una vez que el método de servicio finaliza, el modo de descarga de sesión se revierte a nunca.

También hay una opción para no abrir la sesión en el filtro. Cada llamada a la capa de servicio abriría una sesión separada. & transacción: una vez realizada la llamada de servicio, la sesión no se cierra, sino que se registra para cierre diferido. La sesión se cerrará después de que se complete el procesamiento de solicitud web.

Spring proporciona OpensessionInViewFilter que funciona como se describió anteriormente. Así que ignora el artículo wiki de jboss y simplemente configura el OpensessionInViewFilter: todo estará bien.

SessionFactory.getCurrentSession() - internamente crea y asigna la sesión a un hilo local. Cada solicitud/hilo tendrá su propia sesión. Una vez que se complete el proceso de solicitud web, la sesión se cerrará. Desde dentro de su código solo necesita usar SessionFactory.getCurrentSession() y no tiene que cerrarlo. El ejemplo de código en la página wiki de jboss es incorrecto: debe tener una SessionFactory.getCurrentSession(). Close() en el bloque finally.O pueden estar usando una transacción JTA y se ha configurado hibernación para abrir/cerrar sesión junto con la transacción JTA.

+0

He estado yendo de aquí para allá y luego hasta allí, omitiendo la web sobre este tema durante una semana ... y esa es la primera vez que he leído que Spring tiene un filtro OpenSessionInView. Gracias. – Marvo

+0

Hombre, eso simplemente funciona muy bien. ¡Gracias! – Marvo

+0

Siempre pensé que funcionaría como una transacción. Pero realmente la transacción está limitada por @Transactional de primavera. Gracias por la explicación. –

0

No es un problema si el filtro crea una sesión para cada solicitud, porque las sesiones provienen de un grupo de sesiones y se reutilizarán. Desde la vista del sistema operativo, no pasa nada.

Una sesión de hibernación es, de hecho, una conexión tcp (o socket/pipe) al servidor de la base de datos. El costo de la creación de conexión de db es muy dependiente del tipo sql (postgresql es notablemente malo en esto, aunque es muy bueno en todo). Pero no significa realmente nada, porque hibernate reutiliza las conexiones de la base de datos.

La solución de filtro de hibernación simple inicia una nueva transacción en la sesión para cada solicitud, también. Es transacción desde la vista del SQL: es una consulta "COMIENZO" y "COMPROMISO". Siempre es costoso, y esto debería reducirse.

En mi humilde opinión una posible solución fue, si las transacciones se iniciaron solo en la primera consulta de la solicitud actual. Quizás la primavera tiene algo útil para esto.

+1

Lo que llegamos es utilizar el filtro OpenSessionInView (ver arriba) en combinación con la anotación Spring @Transactional. Hasta ahora, funciona genial. – Marvo

+0

@Marvo No tuve tan buena experiencia con eso. No tienes control, qué pasa exactamente y por qué. En mi último proyecto tuve múltiples conexiones de bases de datos (algunas entidades conectaban la primera, algunas con la segunda) con capas de primavera de dirección cruzada, y algunos de los procesos eran de Quartz iniciado, algunos de la web. La situación era compleja y el principal problema era que, en una anotación o en un AOP, tu control era muy, muy importante, lo que fallaba o dónde estaba el problema. Simplemente funciona o no, pero no se puede ver en ellos. En un entorno de procedimiento claro, es trivial. – peterh

Cuestiones relacionadas