`

Open Session In View模式的基本常识-zhuan

 
阅读更多
 

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是个双刃剑,放在公网上内容多流量大的网站请慎用] 

 

若有什么技术上的问题交流,请联系博主QQ:908599713,在此由衷的感谢每一位程序员……

 

官方文档对其过滤器的解释如下:

 

public class OpenSessionInViewFilterextends OncePerRequestFilter

Servlet 2.3 Filter that binds a Hibernate Session to the thread for the entire processing of the request. Intended for the "Open Session in View" pattern, i.e. to allow for lazy loading in web views despite the original transactions already being completed.

This filter makes Hibernate Sessions available via the current thread, which will be autodetected by transaction managers. It is suitable for service layer transactions via HibernateTransactionManager orJtaTransactionManager as well as for non-transactional execution (if configured appropriately).

NOTE: This filter will by default not flush the Hibernate Session, with the flush mode set to FlushMode.NEVER. It assumes to be used in combination with service layer transactions that care for the flushing: The active transaction manager will temporarily change the flush mode to FlushMode.AUTO during a read-write transaction, with the flush mode reset to FlushMode.NEVER at the end of each transaction. If you intend to use this filter without transactions, consider changing the default flush mode (through the "flushMode" property).

WARNING: Applying this filter to existing logic can cause issues that have not appeared before, through the use of a single Hibernate Session for the processing of an entire request. In particular, the reassociation of persistent objects with a Hibernate Session has to occur at the very beginning of request processing, to avoid clashes with already loaded instances of the same objects.

Alternatively, turn this filter into deferred close mode, by specifying "singleSession"="false": It will not use a single session per request then, but rather let each data access operation or transaction use its own session (like without Open Session in View). Each of those sessions will be registered for deferred close, though, actually processed at request completion.

A single session per request allows for most efficient first-level caching, but can cause side effects, for example on saveOrUpdate or when continuing after a rolled-back transaction. The deferred close strategy is as safe as no Open Session in View in that respect, while still allowing for lazy loading in views (but not providing a first-level cache for the entire request).

Looks up the SessionFactory in Spring's root web application context. Supports a "sessionFactoryBeanName" filter init-param in web.xml; the default bean name is "sessionFactory". Looks up the SessionFactory on each request, to avoid initialization order issues (when using ContextLoaderServlet, the root application context will get initialized after this filter). 

 

 

分享到:
评论

相关推荐

    gssdgv-zhuan-ke-master_java_

    Spring Boot简化了Java应用的初始化和配置,而gssdgv-zhuan-ke在此基础上增加了特定于蚂蚁集团业务需求的功能,使得开发者能够快速构建高性能、高可用的服务。 2. **Readiness Check** Readiness Check是该框架的...

    XUAN-ZHUAN-led.zip_旋转LED_旋转LED 自适应_自适应旋转LED

    "XUAN-ZHUAN-led.zip_旋转LED_旋转LED 自适应_自适应旋转LED"这个压缩包文件内容是关于实现旋转LED自适应转速的程序,其核心目标是让LED屏幕上的字幕能够流畅地滚动,并根据设备的转速自动调整滚动速度,以保持最佳...

    snake-master-cuda8-zhuan_pt.tar

    Deep Snake for Real-Time Instance Segmentation pytorch1.0 cuda8转6个pt

    ban-zhuan.zip_JAVA穷举法搬砖_搬砖_用JAVA穷举法

    在给定的“ban-zhuan.zip_JAVA穷举法搬砖”主题中,我们面对的是一个数学问题,该问题与实际的砖块分配有关。36块砖需要36个人来搬运,其中包括男性、女性和小孩,他们各自有不同的搬运能力。男性每次能搬4块砖,...

    ruby中文转拼音的api

    里面自带api。用法也很简单。 在rails 中 把 pinyin.rb 及 dict 放到lib目录中。 在模型中引入文件。 require "pinyin" ...#=&gt; "zhong1-wen2-zhuan3-han4-yu3-pin1-yin1" py.to_pinyin_abbr_else('劉德華')

    电子技术基础教学完美版-1

    电子技术基础教学完美版电子技术基础教学完美版电子技术基础教学完美版电子技术基础教学完美版电子技术基础教学完美版

    ruby-pingyin ruby中将中文转化成拼音

    要求按照姓名的首字母查找教师。同时拼音的首字母是要来自数据库中现已近存在的姓名的姓氏首字母。...#=&gt; "zhong1-wen2-zhuan3-han4-yu3-pin1-yin1" py.to_pinyin_abbr_else(' 劉德華') #=&gt; "liudh

    zhuan-kai-fa

    7. **设计模式**:是解决常见软件设计问题的经验总结,如单例模式、工厂模式、观察者模式等,它们提供了解决复杂问题的蓝图。 8. **数据库**:理解SQL和NoSQL数据库,如MySQL、PostgreSQL、MongoDB等,以及如何优化...

    zhuan-su-eliang.rar_labview 测_labview 测速_labview测速_labview转速测量_转

    在给定的“zhuan-su-eliang.rar”压缩包中,包含了一个名为“zhuan su eliang.vi”的虚拟仪器(VI),这显然是一款用于转速测量的应用程序。 转速测量是机械工程、汽车工业、电力系统等领域中常见的技术需求。...

    C#代码重构 - Mr.Fu _Zhuan.mobi

    重构是迅速发现并修复有问题的代码的一种高效的方式。在《代码重构(c # & asp.net版)》中首次提供了在c#和asp.net中进行重构的专业方法,您将学习如何运用重构技术管理和修改代码

    zhuan 2.zip

    在这个名为"zhuan 2.zip"的压缩包中,包含了一个支持移动端的转盘抽奖程序。这个程序的核心是通过JavaScript实现,使得用户可以通过点击来触发抽奖过程,从而增加用户体验的趣味性和参与度。 首先,我们来看“转盘...

    zhuan_java_untilgw8_android_

    在这个项目中,我们可以深入学习到Java编程语言、Android应用开发的基础知识以及游戏设计的一些基本原理。 1. **Java编程语言**:Java是Android应用开发的主要语言,它是一种面向对象的、跨平台的编程语言,具有...

    自媒体新媒体软件工具自媒体zhuan钱秘诀资料

    自媒体新媒体软件工具自媒体zhuan钱秘诀资料

    soho网络zhuan钱的体会.doc

    1. 自主编辑的网站和商城:这是SOHO者的基本工具,通过建立个人或专业网站,展示产品或服务,吸引客户并进行在线交易。学习如何设计、优化网站以及利用电子商务平台进行销售是必要的技能。 2. 网络建设与营销知识:...

    Slugify:一个将字符串转换为slug格式的类库

    // 输出: "zhe-shi-yi-ge-xu-yao-zhuan-huan-de-zhong-wen-zi-fu-chuan" ``` 在上述代码中,`slugify()`方法接收一个字符串作为参数,并返回对应的slug形式。注意到,中文字符会被转换成它们的拼音表示,这是为了...

    z zhuan sec_EH4_EH4Z文件转SEC文件_

    标题中的"z zhuan sec_EH4_EH4Z文件转SEC文件_"表明我们正在处理一个涉及到将EH4或EH4Z格式的文件转换为SEC格式的议题。这个过程可能涉及到特定的工具、编程语言或者协议,尤其是在嵌入式系统中,这些文件格式通常与...

    Map_out.rar_Map o_mapgis_mapgis noteo_mapgis zhuan jpg_out

    "Map o_mapgis_mapgis noteo_mapgis zhuan jpg_out"这部分可能是描述了这个压缩包的主要功能或者过程,即MapGIS的二次开发功能,用于将MapGIS的地图数据转换成JPG格式的光栅图像。"o_mapgis_mapgis noteo_mapgis...

    2.6.14 内核移植说明文档(zhuan)

    ### 2.6.14 内核移植与YAFFS文件系统支持详解 #### 一、2.6.14 内核移植步骤 **1.... - **背景**: 如果您使用的是其他人移植好的内核版本,则在开始编译之前应该清除中间文件。这是为了避免因使用的交叉编译工具不同...

    ann(zhuan).rar_ANN

    本人转的别人写的人工神经网络的学习体会与感受,真是受益匪浅啊!

    java面试题以及技巧

    │ 公司培训文档-混淆的基本概念.doc │ 基本算法.doc │ 孙卫琴精通struts.基于MVC的.java.web设计与开发.pdf │ 学习Struts提供的和Form相关标签.txt │ 日企编码规范.doc │ 电信盈科面试题.pdf │ 速算.txt │ ...

Global site tag (gtag.js) - Google Analytics