`

Open Session In View探讨

阅读更多
 在没有使用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 Viewrequestsession绑定到当前thread期间一直保持hibernate sessionopen状态,使sessionrequest的整个期间都可以使用,如在View层里PO也可以lazy loading数据,如 ${ company.employees }。当View 层逻辑完成后,才会通过FilterdoFilter方法或InterceptorpostHandle方法自动关闭session


OpenSessionInViewInterceptor配置
  1. <beans>
  2. <bean name="openSessionInViewInterceptor"
  3. class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor">
  4. <property name="sessionFactory">
  5. <ref bean="sessionFactory"/>
  6. </property>
  7. </bean>
  8. <bean id="urlMapping"
  9. class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
  10. <property name="interceptors">
  11. <list>
  12. <ref bean="openSessionInViewInterceptor"/>
  13. </list>
  14. </property>
  15. <property name="mappings">
  16. ...
  17. </property>
  18. </bean>
  19. ...
  20. </beans>
OpenSessionInViewFilter配置
  1. <web-app>
  2. ...
  3. <filter>
  4. <filter-name>hibernateFilter</filter-name>
  5. <filter-class>
  6. org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
  7. </filter-class>
  8. <!-- singleSession默认为true,若设为false则等于没用OpenSessionInView -->
  9. <init-param>
  10. <param-name>singleSession</param-name>
  11. <param-value>true</param-value>
  12. </init-param>
  13. </filter>
  14. ...
  15. <filter-mapping>
  16. <filter-name>hibernateFilter</filter-name>
  17. <url-pattern>*.do</url-pattern>
  18. </filter-mapping>
  19. ...
  20. </web-app>

很多人在使用OpenSessionInView过程中提及一个错误:

  1. org.springframework.dao.InvalidDataAccessApiUsageException: Write operations
  2. are not allowed in read-only mode (FlushMode.NEVER) - turn your Session into
  3. FlushMode.AUTO or remove 'readOnly' marker from transaction definition

看看OpenSessionInViewFilter里的几个方法

  1. 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);  } }  
  2. protected Session getSession(SessionFactory sessionFactory) throws DataAccessResourceFailureException {  Session session = SessionFactoryUtils.getSession(sessionFactory, true);  session.setFlushMode(FlushMode.NEVER);  return session; }
  3. 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,使方法拥有写权限。

  1. public static void closeSessionIfNecessary(Session session, SessionFactory sessionFactory)
  2. throws CleanupFailureDataAccessException {
  3. if (session == null || TransactionSynchronizationManager.hasResource(sessionFactory)) {
  4. return;
  5. }
  6. logger.debug("Closing Hibernate session");
  7. try {
  8. session.close();
  9. }
  10. catch (JDBCException ex) {
  11. // SQLException underneath
  12. throw new CleanupFailureDataAccessException("Could not close Hibernate session", ex.getSQLException());
  13. }
  14. catch (HibernateException ex) {
  15. throw new CleanupFailureDataAccessException("Could not close Hibernate session", ex);
  16. }
  17. }

    也即是,如果有不是readOnly的transaction就可以由Flush.NEVER转为Flush.AUTO,拥有insert,update,delete操作权限,如果没有transaction,并且没有另外人为地设flush model的话,则doFilter的整个过程都是Flush.NEVER。所以受transaction保护的方法有写权限,没受保护的则没有。

采用spring的事务声明,使方法受transaction控制
  1.   <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>
  2.     <bean id="userService" parent="baseTransaction">         <property name="target">             <bean class="com.phopesoft.security.service.impl.UserServiceImpl"/>         </property>     </bean>

对于上例,则以save,add,update,remove开头的方法拥有可写的事务,如果当前有某个方法,如命名为importExcel(),则因没有transaction而没有写权限,这时若方法内有insert,update,delete操作的话,则需要手动设置flush model为Flush.AUTO,如

  1. session.setFlushMode(FlushMode.AUTO);
  2. session.save(user);
  3. 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是个双刃剑,放在公网上内容多流量大的网站请慎用。

分享到:
评论

相关推荐

    Hibernate Session释放模式

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

    hibernate中session的管理

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

    课程hibernate的事务和并发.pdf

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

    基于PHP的开源PHP博客平台OpenBlog源码.zip

    1. **MVC(Model-View-Controller)架构**:OpenBlog很可能采用了MVC模式来组织代码,这种设计模式将业务逻辑、数据和用户界面分离,使代码更易于维护和扩展。模型负责处理数据,视图用于显示结果,控制器则协调模型...

    hello_xr_hpp:OpenXR“ hello_xr”示例的端口到OpenXR-Hpp绑定投影

    OpenXR的核心组件包括实例(Instance)、系统(System)、会话(Session)、视图配置(View Configuration)、交换图像(Swapchain)和动作(Action)。在C++中,这些都由对应的类表示,如`xr::Instance`, `xr::...

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

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

    ARdno_OpenXR

    开发者需要理解其核心概念,如会话(Session)、动作(Action)、空间坐标系(Space)和视图配置(View Configuration)。学习如何创建和管理OpenXR实例、会话和交换链,以及如何处理输入事件和渲染是关键。 3. **...

    一次hibernate的优化实践

    - 使用Open Session in View模式需谨慎,因为它可能导致事务边界不清,影响性能。 4. **实体设计与映射优化** - 调整懒加载(Lazy Loading)和急加载(Eager Loading)策略,避免因延迟加载引发的额外查询。 - ...

    Hibernate性能优化:一级缓存

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

    hibernate在单端关联上的lazy策略

    为避免这种情况,可以使用Open Session in View(OSIV)模式或者在需要时主动初始化关联。 4. **性能考量**:虽然懒加载可以提高性能,但过度依赖它可能导致更多的数据库交互,反而降低性能。因此,开发者需要根据...

    Hibernate入门(代码+笔记)

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

    struts-hibernate案例1

    在实际的Open Session In View(OSIV)模式中,Session通常在Controller(或Interceptor)层打开,贯穿整个请求过程,直到响应发送后关闭,这样可以确保在视图层也能访问到新鲜的数据,避免了延迟加载的问题。...

    hibernate抓取策略和懒加载案例

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

    struts_ hibernate_spring

    7. **优化性能**:为了提高效率,可以在Service层缓存部分查询结果,或者使用Open Session in View(OSIV)模式来避免多次打开和关闭Session。 通过以上步骤,我们可以将Struts的控制层、Hibernate的数据访问层和...

    Hibernate配置常见错误

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

    hibernate N+1问题解决办法

    7. **使用Open Session in View(OSIV)模式**: 在Web应用中,通过在视图层保持Session开放,可以在请求结束时一次性加载所有关联数据。但这种方法可能导致事务管理复杂,并可能引发并发问题。 8. **使用Querydsl或...

    《Java EE程序设计》应用型教学探讨.zip

    EJB分为三种类型:会话bean(Session Beans)处理业务逻辑,实体bean(Entity Beans)代表持久化的数据,消息驱动bean(Message-Driven Beans)处理JMS(Java Message Service)消息。理解EJB的工作原理和使用场景...

    Hibernate映射导致的几个异常

    为避免此问题,可以考虑在查询时显式加载关联的数据,或者使用开放会话视图(Open Session In View)模式。另外,使用`@Transactional`注解或在服务层方法中管理事务可以帮助保持会话的生命周期。 2. **`...

    无处不在的Spring AOP事务及踩过的坑

    为避免这种情况,可以在需要时尽早初始化关联数据,或者使用Open Session in View(OSIV)模式。 5. **事务隔离级别**:Spring支持多种事务隔离级别,如READ_UNCOMMITTED、READ_COMMITTED、REPEATABLE_READ、...

    org.springframework.web的jar包.zip

    public void onOpen(Session session) { // ... } // 收到客户端消息时调用 @OnMessage public String onMessage(String message) { // ... } // 连接关闭时调用 @OnClose public void onClose(Session...

Global site tag (gtag.js) - Google Analytics