`

Spring使用OpenSessionInViewFilter解决Hibernate的lazy延时加载问题

 
阅读更多

Spring为我们解决最让人头痛的难题之一,Hibernate的Session的关闭与开启问题。

当hibernate+spring配合使用的时候,如果设置了lazy=true,那么在读取数据的时候,当读取了父数据后,hibernate会自动关闭session,这样,当要使用子数据的时候,系统会抛出lazyinit的错误。

Hibernate 允许对关联对象、属性进行延迟加载,但是必须保证延迟加载的操作限于同一个 Hibernate Session范围之内进行。如果 Service 层返回一个启用了延迟加载功能的领域对象给 Web 层,当 Web层访问到那些需要延迟加载的数据时,由于加载领域对象的 Hibernate Session已经关闭,这些导致延迟加载数据的访问异常。而Spring为我们提供的OpenSessionInViewFilter过滤器为我们很好的解决了这个问题。

OpenSessionInViewFilter主要是保持Session状态知道request将全部页面发送到客户端,这样就可以解决延迟加载带来的问题。

 

如果应用中使用了OpenSessionInViewFilter或者OpenSessionInViewInterceptor,所有打开的session会被保存在一个线程变量里。在线程退出前通过OpenSessionInViewFilter或者OpenSessionInViewInterceptor断开这些session。为什么这么做?这主要是为了实现Hibernate的延迟加载功能。基于一个请求一个hibernate session的原则。

 它有两种配置方式OpenSessionInViewInterceptor和OpenSessionInViewFilter(具体参看SpringSide),功能相同,只是一个在web.xml配置,另一个在application.xml配置而已。

spring中对OpenSessionInViewFilter的描述如下:
它是一个Servlet2.3过滤器,用来把一个Hibernate Session和一次完整的请求过程对应的线程相绑定。目的是为了实现"Open Session in View"的模式。
例如: 它允许在事务提交之后延迟加载显示所需要的对象。

这个过滤器和 HibernateInterceptor 有点类似:它是通过线程实现的。无论是没有事务的应用,还是有业务层事务的应用(通过HibernateTransactionManager 或
JtaTransactionManager的方式实现)它都适用。在后一种情况下,事务会自动采用由这个filter绑定的Session来进行相关的操作以及根据实际情况完成提交操作。

如果使用struts2,此监听器应该在struts2的监听器前面

<!--OpenSessionInViewFilter 解决延迟加载问题-->  
        <filter>  
                <filter-name>OpenSessionInViewFilter</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>OpenSessionInViewFilter</filter-name>  
                <url-pattern>/*</url-pattern>  
        </filter-mapping>  

  

 

对于OpenSessionInView的配置中,singleSession应该设置为true,表示一个request只能打开一个 session,如果设置为false的话,session可以被打开多个,这时在update、delete的时候会出现打开多个session的异常。但是当设置为true的时候,系统的性能会因为用户的网络状况受到影响,当request在生成页面完成后,session才会被释放,所以如果用户的网络状况比较差,那么连接池中的链接会迟迟不被回收,造成内存增加,系统性能受损。但是如果不用这种方法的话,lazy模式有体现不出它的优点,用?不用?两难啊。。。。。。

 

    尽管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是个双刃剑,放在公网上内容多流量大的网站请慎用。
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
由于OpenSessionInViewFilter把session绑在当前线程上,导致session的生命周期比事务要长,这期间所有事务性操作都在复用这同一个session,由此产生了一些“怪问题”:
例如出现如下错误:
     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 在把session绑在当前线程上的时候,会把session的flush mode 设为FlushMode.NEVER,因此,如果某个方法没有事务或者有只读事务,则不能对session做insert,update,delete操作,除非事先把session的flush mode手动设为auto
方案:
1、将singleSession设为false,这样只要改 web.xml,缺点是Hibernate Session的Instance可能会大增,使用的JDBC Connection量也会大增,如果Connection Pool的maxPoolSize设得太小,很容易就出问题。<!-- singleSession默认为true,若设为false则等于没用OpenSessionInView -->
2、在控制器中自行管理Session的FlushMode,麻烦的是每个有Modify的Method都要多几行程式
session.setFlushMode(FlushMode.AUTO);
session.update(user);
session.flush();
3、Extend OpenSessionInViewFilter,Override protected Session getSession(SessionFactory sessionFactory),将FlushMode直接改为Auto。
4、让方法受Spring的事务控制(service和配置文件对应)

分享到:
评论

相关推荐

    hibernate 中 fetch=FetchType.LAZY 懒加载失败处理方法

    Hibernate 中 fetch=FetchType.LAZY 懒加载失败处理方法可以通过使用 OpenSessionInViewFilter 或者 Hibernate 的 initialize 方法来解决。这些方法可以确保 Hibernate 的懒加载特性能够正常工作,从而提高应用程序...

    Struts2+Spring+hibernate中对action的单元测试环境搭建[总结].pdf

    解决这个问题的方法有两种:一种是在 web.xml 中使用 Spring 提供的 OpenSessionInViewFilter,另一种是在 application.xml 中配置 OpenSessionInViewFilter。前者通用,后者只能用于 SpringMVC 结构中。 最后,...

    spring管理struts和hibernate

    ### Spring管理Struts与Hibernate详解 #### 一、Spring整合Struts 在Web开发中,Struts是一个基于MVC设计模式的开源框架,它能够帮助开发者构建可维护性高、结构清晰的应用系统。Spring框架则提供了强大的依赖注入...

    解决Lazy最有效的方法

    在探讨“解决Lazy最有效的方法”这一主题时,我们深入剖析了Servlet中处理懒加载(Lazy Loading)的技术细节,特别是如何在Java环境下优化资源管理,确保应用性能与响应速度。以下将从标题、描述以及部分代码片段出发...

    OpenSessionInViewFilter

    OpenSessionInViewFilter个人学习总结

    spring+struts+hibernate的配置文档

    在企业级应用开发中,Spring、Struts 和 Hibernate 这三个框架的结合使用非常普遍,通常被称为 SSH(Spring+Struts+Hibernate)架构。本文将详细解析给定配置文档中的关键知识点,并深入探讨其背后的原理。 #### 1....

    Struts,Spring与hibernate集成

    10. **处理Hibernate延迟加载问题**:为了解决由于Session生命周期和HTTP请求生命周期不匹配导致的延迟加载问题,可以使用OpenSessionInViewFilter。这个过滤器确保Session在请求结束时才关闭,从而能正确处理延迟...

    Struts+Hibernate+Spring的基本流程

    Struts+Hibernate+Spring(SSH)整合是Java Web开发中常见的技术栈,它结合了三个强大的框架,分别负责MVC架构、对象关系映射(ORM)以及依赖注入和AOP(面向切面编程)。SSH整合使得开发过程更加高效且易于维护。 ...

    Struts1.x Spring2.x Hibernate3.x DWR2.x整合工具文档v1.00

    为了提高性能,通常会在Spring中使用`OpenSessionInViewFilter`来管理Hibernate的Session。这样可以在整个请求周期内保持Session打开状态,从而避免多次打开和关闭Session带来的性能损失。 ```xml &lt;filter-name&gt;...

    关于OpenSessionInViewFilter的学习

    OpenSessionInViewFilter是Spring框架中一个非常重要的组件,主要用于解决数据访问层(DAO)与视图层(View)之间的事务管理问题。在Web应用中,由于HTTP请求的无状态性,一次请求通常由多个Servlet过滤器、控制器和...

    Struts+hibernate+Spring的整合

    10. **延迟加载问题**:为了处理Hibernate的延迟加载问题,可以使用Spring的`OpenSessionInViewFilter`。这个过滤器确保在一次HTTP请求的整个生命周期内,Hibernate的Session保持打开状态,允许延迟加载在请求结束时...

    struts2 spring hibernate整合要点、注意点

    &lt;filter-class&gt;org.springframework.orm.hibernate5.support.OpenSessionInViewFilter &lt;filter-name&gt;openSessionInViewFilter *.action &lt;!-- Struts2核心过滤器 --&gt; &lt;filter-name&gt;struts2 ...

    懒加载异常解决.docx

    通过配置OpenSessionInViewFilter,可以在很大程度上解决懒加载异常的问题,尤其是在Java Web应用中使用Hibernate等ORM框架时。当然,还需要根据实际项目的具体情况,灵活调整和优化配置,以达到最佳的性能和稳定性...

    spring3和hibernate4整合的lib库

    5. **使用HibernateTemplate或Session工厂**:Spring提供了`HibernateTemplate`,它是`SessionFactory`的包装器,简化了与Hibernate的交互。或者可以直接使用SessionFactory的代理,例如`OpenSessionInViewFilter`,...

    struts2.3+spring3.1.2+hibernate4.1.6 配置说明

    这个过滤器确保在每次HTTP请求中,都会有一个打开的Hibernate Session,以解决“懒加载”问题。配置中包含了`sessionFactoryBeanName`、`singleSession`和`flushMode`等参数,用于指定SessionFactory的bean名称、...

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

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

    struts+spring+hibernate整合

    Spring4.0、Struts2.3.15、Hibernate4.2.4、jQuery1.9.1涉及到了诸多开发时的细节:ModelDriven、Preparable 拦截器、编写自定义的类型转换器、Struts2 处理 Ajax、OpenSessionInViewFilter、迫切左外连接、Spring ...

    HibernateSpring多数据库解决方案.doc

    在IT行业中,尤其是在Java开发领域,使用Spring框架与Hibernate整合是常见的做法,它们可以提供高效的数据访问和持久化服务。当面临多数据库的场景时,如何实现读写分离或者不同的业务逻辑对应不同的数据库,就显得...

    struts2.1+spring3.0+hibernate3.3整合

    - 使用Spring的`CharacterEncodingFilter`来统一处理字符编码问题,例如设置为`UTF-8`。 #### 四、为项目添加Hibernate支持 1. **依赖引入**:确保项目中包含了Hibernate的核心库以及其他必要的扩展库。对于...

    Spring hibernate opensessioninview

    该模式的核心在于通过Spring提供的`OpenSessionInViewFilter`过滤器,在视图渲染过程中保持Hibernate Session的打开状态,从而简化了事务管理,并避免了一些常见的懒加载异常。 #### 一、OpenSessionInViewFilter...

Global site tag (gtag.js) - Google Analytics