iberck
11/5/2015 - 5:25 PM

Open Session In View Pattern

Open Session In View Pattern

Open Session In View

El problema que OSIV resuelve es un desajuste entre la sesión de hibernate y su ciclo de vida y la forma en la que trabajan las tecnologías de vista del lado servidor.

En una aplicación típica de java la capa de servicio hace queries con datos para construir la vista. Sin embargo habrá datos que no sean cargados hasta que sean necesarios (lazy loaded) con la condición que haya una sesión abierta, y allí es donde empieza el problema.

Entre el momento en que la capa de servicio termina su ejecución y el momento en que la vista es renderizada, hibernate ya ha hecho commit de la tx y cerrado la sesión. Cuando la vista intenta cargar los datos que no fueron cargados en el query (lazy load), encuentra que la sesión ha sido cerrada causando LazyInitializationException.

La solución de OSIV.

OSIV resuelve este problema asegurándose que la sesión de hibernate permanezca abierta hasta que se termine de renderizar la vista, y de ahí el nombre del patrón.

Gracias a que la sesión se mantiene abierta, ya no ocurren más LazyInitializationExceptions. La sesión se mantiene abierta gracias a un filtro que es agregado al procesamiento del request.

En el caso de JPA el OpenEntityManagerInViewFilter creará un entity manager (sesión de hibernate) al inicio del request y luego lo unirá al thread del request.

Luego la capa de servicio será ejecutada y las transacciones commited/rollback sin que el transaction manager borre la sesión del thread después de hacer commit/rollback.

Cuando comienza el renderizado de la vista, el transaction manager revisará si existe una sesión unida al thread del request, si existe la usuará en vez de crear una nueva.

Después de que el request es procesado, el filtro soltará a la sesión del thread.

El resultado final es que la misma sesión utilizada para hacer commit de las transacciones de la capa de servicio se mantiene abierta y agarrada al thread del request, permitiendo que el renderizado de la vista pueda cargar los objetos que se vayan necesitando (lazy loading).

Regresando al problema original

El problema original son las LazyInitializationException. Sin embargo esta excepción es una advertencia de que un query no está bien escrito en la capa de servicio.

Cuando se construye una vista, el desarrollador sabe a priory qué datos se necesitan y puede asegurarse que los datos que se necesitarán en la vista sean leidos por completo antes de que comience el renderizado.

Muchas relaciones por ejemplo one-to-many utilizan lazy loading por default, sin embargo el comportamiento puede ser reescrito en los queries utlizando la siguiente sintaxis:

select p FROM Person p left join fetch p.invoices

Esto significa que lazy loading puede ser apagado dependiendo del tipo de datos necesarios en la vista.

Pros de OSIV

La principal ventaja de OSIV es que ayuda a trabajar con el ORM de una forma más transparente:

  • Se escriben menos queries manualmente
  • Se requiere menor comprensión sobre la sesión de hibernate y cómo solventar las LazyInitializationExceptions.

Contras de OSIV

OSIV es fácil de abusar y accidentalmente introducir el problema N+1 en la aplicación lo cual puede llevar a problemas de rendimiento. La alternativa es utilizar queries que carguen explicitamente los datos que se vayan a utilizar en la vista dependiendo del caso de uso.

Formas de implementar OSIV

TODO: OSIVFIlter OSIVInterceptor?

Grails y Open Session in View

The open session in view (OSIV) pattern is common when using Hibernate, and Grails implements it with the GrailsOpenSessionInViewInterceptor class (which extends the org.spring framework.orm.hibernate3.support.OpenSessionInViewInterceptor Spring class). This interceptor opens a Hibernate session at the beginning of each request, and flushes and closes it after it’s finished.

This is primarily there for lazy-loaded one-to-many collections and many-to-one relationships. If there wasn’t an open session, after loading the instance, it would immediately become disconnected. This is because GORM uses an org.springframe work.orm.hibernate3.HibernateTemplate to do the querying and it has logic to use an existing session using SessionFactoryUtils.getSession() or create one if none is active. When it gets an active session, it doesn’t close it because it didn’t open it, but if it has to create one, then it will close it. This disconnects all loaded instances, so trying to access a collection would throw an exception. Because the OpenSessionInViewInterceptor opens a session and registers it in a ThreadLocal (via SessionFactoryUtils), this keeps the session active, and the collections and relationships can be resolved.

Referencia

http://blog.jhades.org/open-session-in-view-pattern-pros-and-cons/

http://cursohibernate.es/doku.php?id=patrones:osiv