hibernate OpenSessionInView

一、什么是OpenSessionInView

在hibernate中使用load方法时,并未把数据真正获取时就关闭了session,当我们真正想获取数据时会迫使load加载数据,而此时session已关闭,所以就会出现异常。 比较典型的是在MVC模式中,我们在M层调用持久层获取数据时(持久层用的是load方法加载数据),当这一调用结束时,session随之关闭,而我们希望在V层使用这些数据,这时才会迫使load加载数据,我们就希望这时的session是open着得,这就是所谓的Open
Session In view 。 我们可以filter来达到此目的。下面的代码初步解决了此问题:

public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain){

try{

Session session = ...SessionFactory.getCurrentSeesion(); //得到session对象

tx = session.beginTransaction(); //开启事务

chain.doFliter(request,response); //传递给下一个

tx.commit(); //提交事务

}catch (Exception e){

//出现异常,回滚事务

}

}

简析:当请求到达时,会首先被此拦截器拦截,当数据经过获取并在V层显示完毕后,回到此Filter内部,此时提交事务-->关闭session。

二、spring的osiv解决方案

OpenSessionInViewFilter [全名:org.springframework.orm.hibernate3.support.OpenSessionInViewFilter]是Spring提供的一个针对Hibernate的一个支持类,其主要意思是在发起一个页面请求时打开Hibernate的Session,一直保持这个Session,直到这个请求结束,具体是通过一个Filter来实现的。

由于Hibernate引入了Lazy Load特性,使得脱离Hibernate的Session周期的对象如果再想通过getter方法取到其关联对象的值,Hibernate会抛出一个LazyLoad的Exception。所以为了解决这个问题,Spring引入了这个Filter,使得Hibernate的Session的生命周期变长。

有两种方式可以配置实现OpenSessionInView,分别是OpenSessionInViewInterceptor和OpenSessionInViewFilter,功能完全相同,只不过一个在web.xml配置,另一个在application.xml配置而已。我个人比较倾向配置在application.xml里,因为web.xml里配置的东西的太多的话容易发生冲突,虽然可以调整,但是毕竟多了个麻烦。

OpenSessionInViewInterceptor配置:

<beans>

<bean name="openSessionInViewInterceptor" class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor">

<property name="sessionFactory">

<ref bean="sessionFactory"/>

</property>

</bean>

<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">

<property name="interceptors">

<list>

<ref bean="openSessionInViewInterceptor"/>

</list>

</property>

<property name="mappings">

......

</property>

</bean>

......

</beans>

OpenSessionInViewFilter配置: (此监听器应该在struts2的监听器前面)

<web-app>

......

<filter>

<filter-name>hibernateFilter</filter-name>

<filter-class>

org.springframework.orm.hibernate3.support.OpenSessionInViewFilter

</filter-class>

<init-param>

<param-name>singleSession</param-name>

<param-value>true</param-value>

</init-param>

</filter>

......

<filter-mapping>

<filter-name>hibernateFilter</filter-name>

<url-pattern>*.do</url-pattern>

</filter-mapping>

......

</web-app>

OpenSessionInViewFilter是Spring提供的一个针对Hibernate的一个支持类,其主要意思是在发起一个页面请求时打开Hibernate的Session,一直保持这个Session,直到这个请求结束,具体是通过一个Filter来实现的。

由于Hibernate引入了Lazy Load特性,使得脱离Hibernate的Session周期的对象如果再想通过getter方法取到其关联对象的值,Hibernate会抛出一个LazyLoad的Exception。所以为了解决这个问题,Spring引入了这个Filter,使得Hibernate的Session的生命周期变长。

首先分析一下它的源码,可以发现,它所实现的功能其实比较简单:

Java代码  

  1. SessionFactory sessionFactory = lookupSessionFactory(request);  
  2. Session session = null;  
  3. boolean participate = false;  
  4.   
  5. if (isSingleSession()) {  
  6.     // single session mode  
  7.     if (TransactionSynchronizationManager.hasResource(sessionFactory)) {  
  8.     // Do not modify the Session: just set the participate flag.  
  9.     participate = true;  
  10.        }    else {  
  11.     logger.debug("Opening single Hibernate Session in OpenSessionInViewFilter");  
  12.     session = getSession(sessionFactory);  
  13.     TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));  
  14.     }  
  15. } else {  
  16.     // deferred close mode  
  17.     if (SessionFactoryUtils.isDeferredCloseActive(sessionFactory)) {  
  18. // Do not modify deferred close: just set the participate flag.  
  19.     participate = true;  
  20.     } else {  
  21.     SessionFactoryUtils.initDeferredClose(sessionFactory);  
  22.     }  
  23. }  
  24.   
  25. try {  
  26.     filterChain.doFilter(request, response);  
  27. } finally {  
  28.     if (!participate) {  
  29.             if (isSingleSession()) {  
  30.                 // single session mode  
  31.         TransactionSynchronizationManager.unbindResource(sessionFactory);  
  32.         logger.debug("Closing single Hibernate Session in OpenSessionInViewFilter");  
  33.         closeSession(session, sessionFactory);  
  34.     }else {  
  35.         // deferred close mode  
  36.         SessionFactoryUtils.processDeferredClose(sessionFactory);  
  37.     }  
  38. }  
  39. }  

在上述代码中,首先获得SessionFactory,然后通过SessionFactory获得一个Session。然后执行真正的Action代码,最后根据情况将Hibernate的Session进行关闭。整个思路比较清晰。

注意,在这里有个2个Tips:
1)通过getSession()获得的这个Session做了一次
session.setFlushMode(FlushMode.NEVER); 有关FlushMode可以参考一下这篇文章。http://www2.matrix.org.cn/resource/article/2006-10-08/Hibernate+FlushMode+NEVER_312bca85-5699-11db-91a0-d98dff0aec60.html
2)Spring对拿到的Session做了一次绑定到当前线程的做法,使得这个Session是线程安全的。

从上述代码其实可以得到一些对我们的开发有帮助的结论:
1)如果使用了OpenSessionInView模式,那么Spring会帮助你管理Session的开和关,从而你在你的DAO中通过HibernateDaoSupport拿到的getSession()方法,都是绑定到当前线程的线程安全的Session,即拿即用,最后会由Filter统一关闭。
2)由于拿到的Hibernate的Session被设置了session.setFlushMode(FlushMode.NEVER); 所以,除非你直接调用session.flush(),否则Hibernate session无论何时也不会flush任何的状态变化到数据库。因此,数据库事务的配置非常重要。(我们知道,在调用org.hibernate.Transaction.commit()的时候会触发session.flush())我曾经见过很多人在使用OpenSessionInView模式时,都因为没有正确配置事务,导致了底层会抛出有关FlushMode.NEVER的异常。

OpenSessionInView这个模式使用比较简单,也成为了大家在Web开发中经常使用的方法,不过它有时候会带来一些意想不到的问题,这也是在开发中需要注意的。
1. 在Struts+Spring+Hibernate环境中,由于配置的问题导致的模式失效
这个问题以前论坛曾经讨论过,可以参考一下下面这个帖子:
http://www.iteye.com/topic/15057

2. OpenSessionInView的效率问题
这个问题也有人在论坛提出过,Robbin曾经做过具体的测试,可以具体参考一下下面这个帖子:
http://www.iteye.com/topic/17501

3. 由于使用了OpenSessionInView模式后造成了内存和数据库连接问题
这个问题是我在生产环境中碰到的一个问题。由于使用了OpenSessionInView模式,Session的生命周期变得非常长。虽然解决了Lazy Load的问题,但是带来的问题就是Hibernate的一级缓存,也就是Session级别的缓存的生命周期会变得非常长,那么如果你在你的Service层做大批量的数据操作时,其实这些数据会在缓存中保留一份,这是非常耗费内存的。还有一个数据库连接的问题,存在的原因在于由于数据库的Connection是和Session绑在一起的,所以,Connection也会得不到及时的释放。因而当系统出现业务非常繁忙,而计算量又非常大的时候,往往数据连接池的连接数会不够。这个问题我至今非常头痛,因为有很多客户对数据连接池的数量会有限制,不会给你无限制的增加下去。

4. 使用了OpenSessionInView模式以后取数据的事务问题
在使用了OpenSessionInView以后,其实事务的生命周期比Session的生命周期来得短,就以为着,其实有相当一部分的查询是不被纳入到事务的范围内的,此时是否会读到脏数据?这个问题我至今不敢确认,有经验的朋友请指教一下。

最后提一下OpenSessionInView模式的一些替代方案,可以使用OpenSessionInViewInterceptor来代替这个Filter,此时可以使用Spring的AOP配置,将这个Interceptor配置到你所需要的层次上去。另外就是只能使用最古老的Hibernate.initialize()方法进行初始化了。

时间: 2025-01-21 14:54:02

hibernate OpenSessionInView的相关文章

java并发编程实践笔记

1, 保证线程安全的三种方法:     a, 不要跨线程访问共享变量     b, 使共享变量是final类型的     c, 将共享变量的操作加上同步 2, 一开始就将类设计成线程安全的, 比在后期重新修复它,更容易. 3, 编写多线程程序, 首先保证它是正确的, 其次再考虑性能. 4, 无状态或只读对象永远是线程安全的. 5, 不要将一个共享变量裸露在多线程环境下(无同步或不可变性保护) 6, 多线程环境下的延迟加载需要同步的保护, 因为延迟加载会造成对象重复实例化 7, 对于volatil

openSessionInView的使用原理及性能分析

看到好多项目中用到了openSessionInView,这样的做法无非是开发方便,可以在JSP页面中操作数据库层方面的业务.下边说下openSessionInView的用法及性能问题. 使用: 1.增加一个Filter,该Filter用来控制事务及数据库的连接管理,代码如下: SessionFactory sessionFactory = lookupSessionFactory(request); Session session = null; boolean participate = fa

springmvc-请教:Spring + Hibernate 无法将数据写入数据库?

问题描述 请教:Spring + Hibernate 无法将数据写入数据库? Spring + Hibernate 无法将数据写入数据 请教: 通过Junit单元测试Service可以将数据写入数据库:但部署访问却无法向数据库写入数据. 1 环境: Spring 3.1.2 Hibernate 4.1.4 Jdk1.6 2 配置: 2.1 Web.xml <!-- Spring ApplicationContext配置文件的路径,可使用通配符,多个路径用,号分隔 此参数用于后面的Spring C

spring-关于hibernate的疑问(不好意思,前两个问题格式有点错误,我改正了下)

问题描述 关于hibernate的疑问(不好意思,前两个问题格式有点错误,我改正了下) public void update(T t) { Session sess = sessionFactory.getCurrentSession(); sess.update(t); } 这个是我用spring+hibernate反向工程生成的一个DAO的函数,可以看到用了seesion,但是我不理解的是,为什么session在update后没有commit(),和close(),难道Hibernate希望

Maven搭建SpringMVC+Hibernate项目详解(转)

  前言      今天复习一下SpringMVC+Hibernate的搭建,本来想着将Spring-Security权限控制框架也映入其中的,但是发现内容太多了,Spring-Security的就留在下一篇吧,这篇主要搭建SpringMVC4.1.4和Hibernate4.3.8,之前也打了好多SpringMVC的,这部分已经非常的熟悉了,毕竟业开发过一年多SpringMVC的,这次持久层采用Hibernate,数据源采用c3p0,数据库暂采用MySQL,主要是想复习一下Hibernate.搭

Master-Slave,Spring,Hibernate,故事曲折离奇,情结跌宕起伏

/** *作者:张荣华 *日期:2008-02-05 **/ 前言,这篇文章写于08年12月份,现在发布出来望同行点评 ------------------------------------------------------------ 本文将要阐述或者讨论的是spring+hibernate和mysql的master-slave模式之间的一些不得不说的故事. 那么开始之前,按照惯例,我们要介绍一下这个两个东西 1,Hibernate,按照惯例,我们不介绍大家都知道的东西. 2, Maste

Hibernate懒加载解析

Hibernate懒加载解析 在Hibernate框架中,当我们要访问的数据量过大时,明显用缓存不太合适, 因为内存容量有限 ,为了减少并发量,减少系统资源的消耗,这时Hibernate用懒加载机制来弥补这种缺陷,但是这只是弥补而不是用了懒加载总体性能就提高了. 我们所说的懒加载也被称为延迟加载,它在查询的时候不会立刻访问数据库,而是返回代理对象,当真正去使用对象的时候才会访问数据库.    实现懒加载的前提:  1 实体类不能是final的 2 能实现懒加载的对象都是被CGLIB(反射调用)改

用 OpenSessionInViewInterceptor 的思路解决 Spring框架中的Hibernate Lazy

众所周知, 为了解决 Hibernate Lazy 问题, Spring 中引入了 OpenSessionInViewInterceptor, 这样虽然解决了页面上的 Lazy Load 问题,却增加了各层之间的偶合性, 如果一个 Lazy 的 Collection 在页面上可以被正确的 load, 但是如果请求不是来自于 HttpServletRequest (比如在 TestCase 或 Service 中希望获取 lazy 的属性), 一般会导致两种错误: 代码 1. 设置了 lazy =

hibernate session 到SpringMVC Controller 层后 为null?

问题描述 basedaoimpl:@AutowiredprivateSessionFactorysessionFactory;publicSessionFactorygetSessionFactory(){returnsessionFactory;}publicvoidsetSessionFactory(SessionFactorysessionFactory){this.sessionFactory=sessionFactory;}publicSessiongetSession(){retur