`

hibernate open session in view

 
阅读更多

<filter>
 <filter-name>hibernateFilter</filter-name>
 <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
 <filter-name>hibernateFilter</filter-name>
 <url-pattern>/*</url-pattern>
</filter-mapping>

这个过滤器的作用是将hibernate的session的关闭延长到视图层,即事务的范围变大了,不是只在dao层或service层,而是延长到了
view层。好处就是在这段范围里hibernate的延迟加载一直都能用。比如:
public class Admin {
 ...
 private Subject admin_Power; // 管理员权限
 ...
 setter/getter...
}

public class Subject {
 ...
 private String sub_name; // 科目名称
 ...
 setter/getter...
}

<table border="1">
<s:iterator value="admin.admin_Power" status="st">
  <tr>
   <td><s:property value="#st.getIndex()+1"></s:property></td>
   <td><s:property value="sub_name"></s:property></td>
  </tr>
 </s:iterator>
</table> 
我们都知道hibernate默认延迟加载,在获得admin时它的admin_Power在事务中若不显示调用不会加载,这样节省内存。当我们把事
务放在dao或者service层时,在其中没有显示的调用admin_Power,这时在view层使用admin.admin_Power时就会说没有加载
admin_Power。报错:failed to lazily initialize a collection of role.
而使用了spring open in view,就可以解决这个问题了。

注:如果使用strut2的话这个过滤器要配置在FilterDispatcher的前面

-------------------------------------------------------------------------------------------------------------------------------

OpenSessionInView 模式用法探讨

    在没有使用Spring提供的Open Session In View情况下,因需要在service(or Dao)层里把session关闭,所以lazy loading true的话,要在应用层内把关系集合都初始化,如company.getEmployees(),否则Hibernatesession already closed Exception 
   Open Session In View
提供了一种简便的方法,较好地解决了lazy loading问题。它有两种配置方式OpenSessionInViewInterceptorOpenSessionInViewFilter(具体参看SpringSide),功能相同,只是一个在web.xml配置,另一个在application.xml配置而已。 
   Open Session In View
requestsession绑定到当前thread期间一直保持hibernate sessionopen状态,使sessionrequest的整个期间都可以使用,如在View层里PO也可以lazy loading数据,如 ${ company.employees }。当View 层逻辑完成后,才会通过FilterdoFilter方法或InterceptorpostHandle方法自动关闭session 
   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配置: 
  <web-app> 
     ...... 
     <filter> 
       <filter-name>hibernateFilter</filter-name> 
       <filter-class> 
           org.springframework.orm.hibernate3.support.OpenSessionInViewFilter 
       </filter-class> 
       <!-- singleSession默认为true,若设为false则等于没用OpenSessionInView --> 
      <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> 
 

  
很多人在使用OpenSessionInView过程中提及一个错误: 
org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.NEVER) - turn your Session into FlushMode.AUTO or remove 'readOnly' marker from transaction definition
 
看看OpenSessionInViewFilter里的几个方法: 
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,FilterChain filterChain) throws ServletException, IOException {  
    SessionFactory sessionFactory = lookupSessionFactory(); 
  logger.debug("Opening Hibernate Session in OpenSessionInViewFilter"); 
  Session session = getSession(sessionFactory); 
   TransactionSynchronizationManager.bindResource( 
    sessionFactory, new SessionHolder(session)); 
     try { 
       filterChain.doFilter(request, response); 
     }finally { 
        TransactionSynchronizationManager.unbindResource(sessionFactory); 
       logger.debug("Closing Hibernate Session in OpenSessionInViewFilter"); 
       closeSession(session, sessionFactory); 
   } 
  } 
  
  protected Session getSession(SessionFactory sessionFactory)throws DataAccessResourceFailureException { 
   Session session = SessionFactoryUtils.getSession(sessionFactory, true); 
 session.setFlushMode(FlushMode.NEVER); 
 return session; 
} 

protected void closeSession(Session session, SessionFactory sessionFactory)throws CleanupFailureDataAccessException { 
   SessionFactoryUtils.closeSessionIfNecessary(session, sessionFactory); 
} 
 

    
可以看到OpenSessionInViewFiltergetSession的时候,会把获取回来的sessionflush mode 设为FlushMode.NEVER。然后把该sessionFactory绑定到TransactionSynchronizationManager,使request的整个过程都使用同一个session,在请求过后再接除该sessionFactory的绑定,最后closeSessionIfNecessary根据该session是否已和transaction绑定来决定是否关闭session。在这个过程中,若HibernateTemplate 发现自当前session有不是readOnlytransaction,就会获取到FlushMode.AUTO Session,使方法拥有写权限。 

public static void closeSessionIfNecessary(Session session, SessionFactory sessionFactory)throws CleanupFailureDataAccessException { 
   if (session == null || TransactionSynchronizationManager.hasResource(sessionFactory)){ 
     return; 
   } 
   logger.debug("Closing Hibernate session"); 
   try { 
     session.close(); 
   }catch (JDBCException ex) { 
     // SQLException underneath 
     throw new CleanupFailureDataAccessException("Could not close Hibernate session", ex.getSQLException()); 
   }catch (HibernateException ex) { 
      throw new CleanupFailureDataAccessException("Could not close Hibernate session", ex); 
   } 
} 
 
    
也即是,如果有不是readOnlytransaction就可以由Flush.NEVER转为Flush.AUTO,拥有insert,update,delete操作权限,如果没有transaction,并且没有另外人为地设flush model的话,则doFilter的整个过程都是Flush.NEVER。所以受transaction保护的方法有写权限,没受保护的则没有。 
    
采用spring的事务声明,使方法受transaction控制 
<bean id="baseTransaction" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true"> 
<property name="transactionManager" ref="transactionManager"/> 
<property name="proxyTargetClass" value="true"/> 
<property name="transactionAttributes"> 
   <props> 
     <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop> 
     <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop> 
     <prop key="load*">PROPAGATION_REQUIRED,readOnly</prop> 
     <prop key="save*">PROPAGATION_REQUIRED</prop> 
     <prop key="add*">PROPAGATION_REQUIRED</prop> 
     <prop key="update*">PROPAGATION_REQUIRED</prop> 
     <prop key="remove*">PROPAGATION_REQUIRED</prop> 
   </props> 
  </property> 
</bean> 
 
   
对于上例,则以save,add,update,remove开头的方法拥有可写的事务,如果当前有某个方法,如命名为importExcel(),则因没有transaction而没有写权限,这时若方法内有insert,update,delete操作的话,则需要手动设置flush modelFlush.AUTO,: 
session.setFlushMode(FlushMode.AUTO);  session.save(user);  session.flush();
 
  
尽管Open Session In View看起来还不错,其实副作用不少。看回上面OpenSessionInViewFilterdoFilterInternal方法代码,这个方法实际上是被父类的doFilter调用的,因此,我们可以大约了解的OpenSessionInViewFilter调用流程: request(请求)->open session并开始transaction->controller->View(Jsp)->结束transactionclose session 
    
一切看起来很正确,尤其是在本地开发测试的时候没出现问题,但试想下如果流程中的某一步被阻塞的话,那在这期间connection就一直被占用而不释放。最有可能被阻塞的就是在写Jsp这步,一方面可能是页面内容大,response.write的时间长,另一方面可能是网速慢,服务器与用户间传输时间久。当大量这样的情况出现时,就有连接池连接不足,造成页面假死现象。 

[Open Session In View是个双刃剑,放在公网上内容多流量大的网站请慎用] 
分享到:
评论

相关推荐

    struts2+hibernate3 open session in view

    总的来说,"Struts2+Hibernate3 Open Session in View"项目展示了如何结合这两种技术,实现高效且可靠的Web应用数据持久化。理解并正确使用OSIV模式,可以帮助开发者避免常见的数据库交互问题,提高应用的稳定性和...

    Open Session in View模式.PPT

    Open Session in View (OSIV) 模式是一种在基于Hibernate的Web应用程序中处理持久化数据的策略,它允许在视图层(例如JSP页面)中安全地访问延迟加载的对象,而无需担心Session已关闭的问题。以下是关于这个模式及其...

    hibernate中session的管理

    3. **Open Session in View (OSIV)**:在视图渲染阶段保持Session打开,以允许最后时刻的懒加载,但需要注意防止Session泄露。 总的来说,Hibernate中Session的管理是保证多线程环境下数据一致性的重要环节。...

    Open_Session_In_View详解.doc

    `Open Session In View`的主要作用是在Web请求的开始阶段打开`Hibernate session`,并在请求结束时自动关闭该session。这样做的好处在于,可以确保在整个请求处理过程中session始终处于可用状态,使得在视图(View)层...

    Hibernate Session释放模式

    3. **Open Session in View(OSIV)模式** OSIV模式旨在解决Web应用中,由于用户请求可能会引发多次数据库操作,而这些操作可能跨多个HTTP请求。在这种模式下,Session在整个HTTP请求周期内保持打开状态,直到请求...

    Hibernate事务管理.

    在没有Spring提供的Open Session In View(OSIV)模式下,事务处理和懒加载(lazy loading)可能会遇到挑战。 懒加载是一种优化策略,允许关联对象在需要时才从数据库加载,而不是在初始加载实体时就全部加载。这...

    集成spring的hibernate懒加载

    在Spring整合Hibernate的情况下,Session通常通过Transaction Management进行管理,比如使用`Open Session in View`(OSIV)模式或者基于注解的事务管理。 当你尝试在Controller层或者视图层访问懒加载的属性时,...

    使用Spring引起的错误

    Open Session In View是一种在Spring框架中常用的技术,用于简化Hibernate中的懒加载(lazy loading)机制。通过保持Hibernate Session在整个请求周期内处于打开状态,可以避免在视图层因为Session关闭而导致的`...

    hibernate的lazy策略forClass

    2. 使用Open Session In View模式,将Session的生命周期扩展到整个HTTP请求,但此方法可能带来事务管理和性能问题。 3. 在需要访问懒加载属性时,确保在Session内进行操作,或者使用`Hibernate.initialize()`手动...

    Hibernate入门(代码+笔记)

    以及开放 session 在视图(Open Session In View,OSIV)模式,确保在Web请求生命周期内保持一个持久化上下文,避免N+1查询问题。 总结来说,本教程涵盖了Hibernate的基础知识,从入门到实体映射,再到复合主键和...

    深入学习hibernate

    在后续章节中,文章涵盖了Hibernate的核心接口与类、标识符生成策略、对象生命周期管理、OSIV(Open Session In View)模式、泛型DAO模式、集合映射、组件映射、各种关联关系的映射(一对一、一对多、多对多)、...

    Struts Spring Hibernate 整合 OpenSessionInView 例子

    为了练手培训,给大家准备的 Open Session In View 的简单例子,纯代码,大家可以参考,其中主要说了六部分内容: 1.通过接口编程 2.通过spring注入dao到 action 3.通过 open session in view filter 支持 延迟加载...

    spring中lazy=“true”的正常读取关联表(用opensessioninview)

    为了解决这个问题,Spring提供了一个过滤器 `OpenSessionInViewFilter` 或者 `OpenSessionInViewInterceptor`,通常简称为OSIV(Open Session In View)模式。 OSIV模式的核心思想是在Controller层和View层之间保持...

    Spring延迟加载和声明式事务处理最终解决方案(修正版)

    1. **Open Session in View Interceptor (OSIV)**:这是Spring MVC中的一个拦截器,它的作用是在整个视图渲染过程中保持Hibernate Session的开放,确保在需要的时候可以进行延迟加载。配置OSIV拦截器后,如在`spring...

    课程hibernate的事务和并发.pdf

    这种方式被称为ThreadLocal Session和Open Session in View模式,能够简化事务和Session的生命周期管理。 在实际应用中,需要确保正确地开启和结束Session及事务,并将其与数据访问操作结合。HibernateUtil类可以...

    Hibernate性能优化:一级缓存

    4. **使用Open Session in View(OSIV)模式**:在Web开发中,为每个HTTP请求开启一个新的会话,可以避免跨请求的一级缓存污染问题,但也要注意防止会话泄漏。 压缩包文件“hibernate_cache_level1”可能包含与一级...

    【北大青鸟内部教程】jsp中关于Hibernate延时加载的问题

    为解决此问题,可以在Controller层或Service层提前加载关联数据,或者使用Hibernate的“开放Session视图”(Open Session in View)模式。 3. **事务管理**:延时加载需要在一个有效的Hibernate Session内进行。在...

    SpringMVC3和hibernate3的整合

    - 使用Spring的Open Session in View(OSIV)模式,处理可能出现的懒加载异常。 - 考虑使用第二级缓存,如Hibernate的 EhCache 插件,提升性能。 - 使用事务管理,确保数据一致性。 通过以上步骤和代码示例,我们...

    Hibernate配置常见错误

    解决方案:理解并合理使用Open Session in View(OSIV)模式,或者在查询时显式调用`Hibernate.initialize()`方法。另外,可以考虑将懒加载改为急加载(Eager Fetching)。 六、HQL查询错误 错误表现:执行HQL语句...

    hibernate抓取策略和懒加载案例

    为了避免这种情况,我们可以使用Open Session in View(OSIV)模式或者在查询时显式启用急切加载。 总的来说,选择合适的抓取策略和恰当使用懒加载是优化Hibernate应用性能的重要手段。开发者应根据业务场景灵活...

Global site tag (gtag.js) - Google Analytics