OpenSessionInViewFilter的作用

OpenSessionInViewFilter的作用

Spring为我们解决Hibernate的Session的关闭与开启问题。

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

(eg: org.hibernate.LazyInitializationException:(LazyInitializationException.java:42)

- failed to lazily initialize a collection of role: cn.easyjava.bean.product.ProductType.childtypes, no session or session was closed

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: cn.easyjava.bean.product.ProductType.childtypes, no session or session was closed)。

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

而Spring为我们提供的OpenSessionInViewFilter过滤器为我们很好的解决了这个问题。OpenSessionInViewFilter的主要功能是用来把一个Hibernate Session和一次完整的请求过程对应的线程相绑定。目的是为了实现"Open Session in View"的模式。例如: 它允许在事务提交之后延迟加载显示所需要的对象。

OpenSessionInViewFilter 过滤器将 Hibernate Session 绑定到请求线程中,它将自动被 Spring 的事务管理器探测到。所以 OpenSessionInViewFilter 适用于 Service 层使用HibernateTransactionManager 或 JtaTransactionManager 进行事务管理的环境,也可以用于非事务只读的数据操作中。

<filter>

        <filter-name>Spring OpenSessionInViewFilter</filter-name>

        <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>

     <init-param>

   

<!--

指定org.springframework.orm.hibernate3.LocalSessionFactoryBean在spring配置文件中的名称,默认值为sessionFactory

     如果LocalSessionFactoryBean在spring中的名称不是sessionFactory,该参数一定要指定,否则会出现找不到sessionFactory的例外

-->

     <param-name>sessionFactoryBean</param-name>

   <param-value>sessionFactory</param-value>

</init-param>

    </filter>

    <filter-mapping>

        <filter-name>Spring OpenSessionInViewFilter</filter-name>

        <url-pattern>/*</url-pattern>

    </filter-mapping>

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/sunsea08/archive/2009/09/12/4545186.aspx

-------------------------------------------------错误问题解决1 ----------------------------------------------------------------------------------------

web.xml原始配置:

<!-- 过滤spring中对于hibernate的session关闭管理 -->

<filter>

   <filter-name>hibernateFilter</filter-name>

   <filter-class>

    org.springframework.orm.hibernate3.support.OpenSessionInViewFilter

   </filter-class>

</filter>

自己写的serviceImpl.java文件中的保存更新方法(我所出现问题的位置是:多行提交的方法),在运行时总报错。如下:

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

后来在网上狂搜解决方案,将web.xml文件改为如下:

<!-- 过滤spring中对于hibernate的session关闭管理 -->

<filter>

      <filter-name>hibernateFilter</filter-name>

         <filter-class>

             org.springframework.orm.hibernate3.support.OpenSessionInViewFilter

         </filter-class>

      <init-param>       

         <param-name>singleSession</param-name>

        <param-value>false</param-value>    

      </init-param>

</filter>

上面的异常解决了,但又报出新的异常,如下:

org.hibernate.HibernateException: Illegal attempt to associate a collection

with two open sessions

解决这个问题的办法就是要把singleSession的值改为true

<init-param>       

         <param-name>singleSession</param-name>

        <param-value>true</param-value>   

</init-param>

我无奈了,这两个错误就好像是相互的,只能解决一个。。。

从网上搜。。还真我出现的这咱情况。。结果如下:

说明一下Open Session in View的作用,就是允许在每次的整个request的过程中使用同一个hibernate session,可以在这个request任何时期lazy loading数据。

如果是singleSession=false的话,就不会在每次的整个request的过程中使用同一个hibernate session,而是每个数据访问都会产生各自的seesion,等于没有Open Session in View。

OpenSessionInViewFilter默认是不会对session 进行flush的,并且flush mode 是 never

代码:

    protected Session getSession(SessionFactory sessionFactory) throws DataAccessResourceFailureException {

       Session session = SessionFactoryUtils.getSession(sessionFactory, true);

       session.setFlushMode(FlushMode.NEVER);

       return session;

    }

看getSession的方式就知道,把flush mode 设为FlushMode.NEVER,这样就算是commit的时候也不会session flush,

如果想在完成request过程中更新数据的话, 那就需要先把flush model设为FlushMode.AUTO,再在更新完数据后flush.

OpenSessionInView默认的FlushMode为

代码:

FlushMode.NEVER

 

可以采用在写保存更新删除代码的时候手动更改FlushMode

代码:

         this.getHibernateTemplate().execute(new HibernateCallback() {

             public Object doInHibernate(Session session) throws HibernateException {

                 session.setFlushMode(FlushMode.AUTO);

                 session.save(user);

                 session.flush();

                 return null;

             }

         });

 

但是这样做太繁琐了,第二种方式是采用spring的事务声明

代码:

     <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="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>

代码:

    <bean id="userService" parent="baseTransaction">

         <property name="target">

             <bean class="com.phopesoft.security.service.impl.UserServiceImpl"/>

         </property>

     </bean>

太巧了,我们的框架就采用了这位前辈所说的第二种方案,但是为什么我把配置文件改成他说的样式还是不行呢?

郁闷中惊奇发现,不是我所有的多行提交都出问题,而只是个别的。经过一翻考虑后,确定自己写的方法体没有

问题了,那么就是方法名了,才发现,还真是方法名的问题。

原来自己写的serviceImpl.java文件的方法名要用“load”“save”“add”“update”“remove”这些词开头,这个就好像是通过这个bean-service.xml文件管理方法名一样,超出这个范围了,hibernate自身的作用就发挥不出来了。

-----------------------------------------------------错误问题解决2------------------------------------------------------------------------------

同时使用ContextLoaderListener和ContextLoaderPlugIn,不要在ContextLoaderPlugIn里面加入applicationContext.xml,只要加入act ion-servlet.xml,OpenSessionInView可生效。

因为ContextLoaderListener保存的对象的是key WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE!而ContextLoaderPlugIn保存的对象的是key是attrName,这个attrName和WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE的值是不一样的,而OpenSessionInViewFilter是从WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE获取spring配置信息的,所以如果将applicationContext.xml以插件的形式配置,则OpenSessionInViewFilter获取不到spring的配置信息,OpenSessionInViewFilter可能会失效。

来源:http://he.rui.rui.blog.163.com/blog/static/9864566220091026105947661/

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

«    2024年11月    »
123
45678910
11121314151617
18192021222324
252627282930
搜索
标签列表
网站分类
最新留言
    文章归档
    友情链接

    Powered By Z-BlogPHP 1.7.3

    Copyright Your WebSite.Some Rights Reserved.闽ICP备11018667号-2