`
toxy
  • 浏览: 72048 次
  • 性别: Icon_minigender_1
  • 来自: 云南.昆明
社区版块
存档分类
最新评论

OpenSessionInView 模式用法探讨

阅读更多
    在没有使用Spring提供的Open Session In View情况下,因需要在service(or Dao)层里把session关闭,所以lazy loading 为true的话,要在应用层内把关系集合都初始化,如 company.getEmployees(),否则Hibernate抛session already closed Exception。
   Open Session In View提供了一种简便的方法,较好地解决了lazy loading问题。它有两种配置方式OpenSessionInViewInterceptor和OpenSessionInViewFilter(具体参看SpringSide),功能相同,只是一个在web.xml配置,另一个在application.xml配置而已。
   Open Session In View在request把session绑定到当前thread期间一直保持hibernate session在open状态,使session在request的整个期间都可以使用,如在View层里PO也可以lazy loading数据,如 ${ company.employees }。当View 层逻辑完成后,才会通过Filter的doFilter方法或Interceptor的postHandle方法自动关闭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);
}

    可以看到OpenSessionInViewFilter在getSession的时候,会把获取回来的session的flush mode 设为FlushMode.NEVER。然后把该sessionFactory绑定到TransactionSynchronizationManager,使request的整个过程都使用同一个session,在请求过后再接除该sessionFactory的绑定,最后closeSessionIfNecessary根据该session是否已和transaction绑定来决定是否关闭session。在这个过程中,若HibernateTemplate 发现自当前session有不是readOnly的transaction,就会获取到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);
   }
}
    也即是,如果有不是readOnly的transaction就可以由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 model为Flush.AUTO,如:
session.setFlushMode(FlushMode.AUTO);  session.save(user);  session.flush();
  尽管Open Session In View看起来还不错,其实副作用不少。看回上面OpenSessionInViewFilter的doFilterInternal方法代码,这个方法实际上是被父类的doFilter调用的,因此,我们可以大约了解的OpenSessionInViewFilter调用流程: request(请求)->open session并开始transaction->controller->View(Jsp)->结束transaction并close session。
    一切看起来很正确,尤其是在本地开发测试的时候没出现问题,但试想下如果流程中的某一步被阻塞的话,那在这期间connection就一直被占用而不释放。最有可能被阻塞的就是在写Jsp这步,一方面可能是页面内容大,response.write的时间长,另一方面可能是网速慢,服务器与用户间传输时间久。当大量这样的情况出现时,就有连接池连接不足,造成页面假死现象。

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

来源:http://calvin.blog.javascud.org/post/46.htm

分享到:
评论

相关推荐

    Spring hibernate opensessioninview

    而在使用这两个框架时,为了更好地管理数据库会话(Session)生命周期,通常会采用`OpenSessionInView`模式。该模式的核心在于通过Spring提供的`OpenSessionInViewFilter`过滤器,在视图渲染过程中保持Hibernate ...

    OpenSessionInView项目整合jar包

    在Java Web开发中,OpenSessionInView(OSIV)模式是一种常见的解决数据持久化问题的设计模式,主要用于Spring框架与Hibernate等ORM工具的集成。这个模式的主要目的是解决在HTTP请求处理过程中,由于Session范围内的...

    Struts Spring Hibernate 整合 OpenSessionInView 例子

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

    第30讲--Spring提供的CharacterEncoding和OpenSessionInView功能

    同时,需要注意的是,OpenSessionInView模式虽然方便,但也会带来潜在的问题,如事务边界不清晰和会话泄漏。因此,在实际应用中,应结合具体需求谨慎使用,并考虑使用更现代的解决方案,如Spring Data JPA的...

    Open_Session_In_View详解.doc

    这个问题通常是由于在`Open Session In View`模式下执行了写操作导致的。因为`Open Session In View`默认采用`FlushMode.NEVER`,这意味着Hibernate不会自动刷新session来同步数据库的变化。为了避免这个问题,可以...

    SSH项目整合示例【OpenSessionInView】所用到的jar包

    OpenSessionInView(OSIV)模式是SSH整合中常见的一种优化策略,它在用户的一次HTTP请求过程中保持Hibernate Session,避免了多次打开和关闭Session,减少了N+1查询问题,提高了性能。 **Spring** 是一个全面的企业...

    Spring提供的CharacterEncoding和OpenSessionInView功能

    SSH框架结合了Struts的MVC设计模式、Spring的依赖注入和事务管理以及Hibernate的持久化能力,为Java Web开发提供了强大的支持。然而,随着Spring Boot的兴起,SSH框架的使用逐渐减少,更多地转向了Spring Boot的开箱...

    SSH整合示例项目 hibernate5.2.3+struts2.5.2+spring4.3.3.zip

    - **二级缓存**:提高数据访问效率,OpenSessionInView模式下配合Spring实现 session级缓存。 **OpenSessionInView模式** OpenSessionInView模式是一种解决数据持久层和Web层之间事务管理的策略。在用户请求到达时...

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

    `lazy="true"` 的使用场景通常是,当一个大型实体类中包含了很多关联的对象,而这些关联对象在大多数情况下并不需要立即加载。例如,一个用户对象可能关联了多个地址、订单等,如果在加载用户时一并加载所有关联数据...

    SSH整合 struts+hibernate+spring

    - **代理模式**:使用代理模式来替代Struts默认的Action实例创建机制,通过Spring上下文获取Action实例,而非直接使用new关键字。 - **Struts与Spring整合的注意事项**: - 避免直接在Action类中访问Spring上...

    HibernateSpring多数据库解决方案.doc

    本方案主要探讨如何在基于Hibernate和Spring框架的环境中实现多数据库的管理,特别是在`OpenSessionInView`模式下的配置。 首先,我们看到在`applicationContext.xml`配置文件中定义了两个数据源,一个用于读操作...

    Hibernate分页总结

    在使用Spring框架时,推荐采用OpenSessionInView模式,确保请求处理的整个过程中数据库会话保持打开。这样可以避免因事务过早关闭导致的懒加载问题,但需要注意不要在视图层进行大数据量的分页查询,以免内存溢出。 ...

    hibernate 中的lazy属性祥解.txt

    为了避免这种情况,可以在访问关联对象前检查Session是否仍然打开,或者使用OpenSessionInView模式来管理Session的生命周期。 ### 结论 `lazy`属性是Hibernate框架中一个非常重要的特性,它通过延迟加载关联对象来...

    TSH练习例子

    文档讨论了HibernateSession的使用,提到了Session-per-Transaction(每个事务一个会话)和OpenSessionInView(在视图中打开会话)两种模式。前者更强调事务的一致性,后者则提高了懒加载性能,但可能会导致脏读问题...

    百度面试题

    - MVC(Model-View-Controller)模式在Web开发中广泛使用。Model负责业务逻辑,View负责显示,Controller处理用户请求并协调Model和View。设计时要关注URL映射、控制器设计、视图渲染及模型数据传递等。 以上知识...

    java程序员ssh面试常见题

    - **使用示例**:可以通过`getHibernateTemplate()`方法获取`HibernateTemplate`实例,并使用它来进行保存、更新、删除和查询等操作。 - **事务管理**:Spring可以管理Hibernate的事务,简化了事务控制代码。 - *...

    SSH面试总结(非常全)

    当使用`getHibernateTemplate()`方法时,Spring会自动管理事务,无需显式提交或回滚,提高了开发效率和代码的健壮性。 ### 结论 综上所述,掌握SSH框架的深度知识不仅能帮助开发者在面试中脱颖而出,更能显著提升...

    百度面试题汇总(java)

    9. **OpenSessionInView模式下的Transaction、数据库连接、HibernateSession管理**:该模式用于将一个持久化上下文的生命周期与HTTP请求绑定起来,简化事务管理。 10. **Error、CheckedException和Unchecked...

    关于OpenSessionInViewFilter的学习

    通过阅读《OpenSessionInViewFilter说明.doc》文档,你可以更深入地了解其内部实现细节、配置方法以及如何在实际项目中合理使用。这个文档应该包含了OpenSessionInViewFilter的源码分析、配置示例以及常见问题的解答...

    jsf + spring +hibernate 自己做的一个例子,主要是看一些基本配置

    在整合JSF、Spring和Hibernate时,通常会使用Spring的OpenSessionInView模式来处理数据库会话。这能确保在HTTP请求的整个生命周期内保持有效的Hibernate Session,从而避免可能出现的数据访问问题。 至于压缩包中的...

Global site tag (gtag.js) - Google Analytics