`
jxh118
  • 浏览: 124174 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

Open Session In View解决session.close问题

阅读更多

在没有使用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笔记

    Open Session in View(OSIV)模式是一种常见的Hibernate优化模式,主要用于提高读取操作的性能。在这种模式下,Session在整个HTTP请求周期内保持打开状态。 ##### OSIV 实现方式 - **Servlet Filter 方式**:最常见...

    EurekaLog_7.5.0.0_Enterprise

    8)....Added: Exception line highlighting in disassember view in EurekaLog exception dialog and Viewer 9)....Added: Detection/logging Delphi objects in disassembly view 10)..Added: Support for multi-...

    JCreatorV4

    You can open multiple files in the Open dialogue box, by holding down the Shift or Ctrl key down as you select each file. You can press ESC to return from Full Screen mode to normal mode.

    UE(官方下载)

    In this tutorial, we'll cover some of the basics of Unicode-encoded text and Unicode files, and how to view and manipulate it in UltraEdit. Search and delete lines found UEStudio and UltraEdit provide...

    Android多媒体功能开发-使用Camera2框架拍照的例子

    public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) { super.onCaptureCompleted(session, request, result); ...

    android TextureVIew实现摄像头预览和拍照

    captureSession.close(); camera.close(); } }; CaptureRequest.Builder captureRequestBuilder = camera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); captureRequestBuilder.addTarget...

    python3.6.5参考手册 chm

    What’s New in Python What’s New In Python 3.6 Summary – Release highlights New Features PEP 498: Formatted string literals PEP 526: Syntax for variable annotations PEP 515: Underscores in ...

    初学ASP基础教材很基础的东西

    同时,学会使用View Source查看浏览器接收到的HTML源码,以及使用开发人员工具进行调试,将有助于找出和解决ASP代码中的问题。 学习ASP还需要掌握一些Web开发的基本概念,如HTTP协议、URL、CGI(通用网关接口)等。...

    Bloodshed Dev-C++

    * Multi-select files in project-view (when "double-click to open" is configured in Environment Settings) * Resource files are treated as ordinary files now * Updates in "Project Options/Files" code * ...

    android camera2实现实时预览和拍照

    textureView = findViewById(R.id.texture_view); textureView.setSurfaceTextureListener(textureListener); } private final TextureView.SurfaceTextureListener textureListener = new TextureView....

    springmybatis

    session.close(); } } } 现在运行这个程序,是不是得到查询结果了。恭喜你,环境搭建配置成功,接下来第二章,将讲述基于接口的操作方式,增删改查。 整个工程目录结构如下: 除非申明,文章均为一号门原创,...

    ICS delphixe10源码版

    .\Source\Include (was Delphi\Vc32) .inc files (including OverbyteIcsDefs.inc) .\Source\Extras (was Delphi\Vc32) Extra source code not built into packages .\Source\zobj125 (was Delphi\Vc32) ZLIB C OBJ ...

    ASP好东西,要毕业了,一点一点的发给大家,不防下载看看!

    5. **ASP.NET的进化**:虽然ASP的经典版本已经比较老旧,但其后续的ASP.NET提供了更强大的功能和性能,引入了面向对象编程、控件模型、以及更丰富的框架支持,如MVC(Model-View-Controller)和Web Forms。...

    FastReport.v4.15 for.Delphi.BCB.Full.Source企业版含ClientServer中文修正版支持D4-XE5

    - fixed bug with URLs in Open Document Text and Open Document Spreadsheet exports - fixed format string in XLS OLE export - fixed format string in XLS BIFF8 export - fixed output of the check boxes ...

    android自定义相机连拍

    需要注意的是,实际开发中可能还需要处理权限请求、相机旋转、对焦、曝光等问题,以及根据不同的设备和API级别进行兼容性调整。希望这篇详解能帮助初学者快速理解和实现Android自定义相机连拍功能。

    计算机网络第六版答案

    Many of these data centers are located in, or close to, lower tier ISPs. Therefore, when Google delivers content to a user, it often can bypass higher tier ISPs. What motivates content providers to ...

    J2EE复习题1

    1. MVC模式:MVC(Model-View-Controller)模式是一种软件设计模式,广泛应用于Web应用开发中。M表示模型,负责处理业务逻辑和数据;V表示视图,负责展示用户界面;C表示控制器,作为模型和视图之间的桥梁,处理用户...

    android camera拍照

    使用`Camera2`时,你需要创建`CaptureRequest`,设置`CaptureSession`,然后调用`capture()`或`captureSingleRequest()`方法。 总结一下,创建一个自定义的Android相机应用涉及以下几个步骤: 1. 添加相机权限。 2....

Global site tag (gtag.js) - Google Analytics