OpenSessionInView详解

一般在SSH配置中,web.xml都是这样配置的:

<?xml version="1.0" encoding="UTF-8"?>

<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee

    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

 

    <!-- 配置上下文 -->

    <!-- 作用:定义Spring配置文件位置,可以定义多个文件,也可以使用通配符 -->

    <context-param>

       <param-name>contextConfigLocation</param-name>

       <param-value>

           /WEB-INF/classes/applicationContext*.xml

       </param-value>

    </context-param>

 

    <!-- 配置Spring过滤器 -->

    <!-- 作用:启动web应用,就加载Spring,让Spring管理Bean -->

    <listener>

       <listener-class>

           org.springframework.web.context.ContextLoaderListener

       </listener-class>

    </listener>

 

    <!-- 解决hibernate延迟加载出现的问题,要放在Struts2过滤器之前 -->

    <!-- 作用:Spring管理hibernateSession,在事务管理的类执行完后,不立刻关闭Session

        而将Session保存在一个线程变量中,在线程退出前关闭Session;这样在整个request过程中

        始终使用一个session,也就可以在request的任何时期lazy loading数据。

        主要是为了实现hibernate的延迟加载功能 -->

    <filter>

       <filter-name>lazyLoadingFilter</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>

 

    <!-- Struts2过滤器 -->

    <filter>

       <filter-name>struts2</filter-name>

       <filter-class>

           org.apache.struts2.dispatcher.FilterDispatcher

       </filter-class>

    </filter>

 

    <!-- 解决hibernate延迟加载出现的问题,仍需要放在Struts2过滤器的filter-mapping之前 -->

    <filter-mapping>

       <filter-name>lazyLoadingFilter</filter-name>

       <url-pattern>*.action</url-pattern>

    </filter-mapping>

    <!-- Struts2过滤器的filter-mapping -->

    <filter-mapping>

       <filter-name>struts2</filter-name>

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

    </filter-mapping>

 

    <welcome-file-list>

       <welcome-file>index.jsp</welcome-file>

    </welcome-file-list>

</web-app>

那其中的OpenSessionInViewFilter是干什么用的呢

spring中对OpenSessionInViewFilter的描述如下:

它是一个Servlet2.3过滤器,用来把一个Hibernate Session和一次完整的请求过程对应的线程相绑定目的是为了实现"Open Session in View"的模式。

假设在应用中Hibernate是通过spring 来管理它的session如果在你的应用中没有使用OpenSessionInViewFilter或者OpenSessionInViewInterceptorsession会在transaction结束后关闭。

例如:项目的事务如下配置:

<!-- 配置事务管理器 -->

    <bean id="transactionManager"

    class="org.springframework.orm.hibernate3.HibernateTransactionManager">

       <property name="sessionFactory">

           <ref bean="sessionFactory" />

       </property>

    </bean>

<!-- 配置事务传播特性,配置add,updatedelete开头的方法,事务的传播特性为required -->

    <tx:advice id="txAdvice" transaction-manager="transactionManager">

       <tx:attributes>

           <tx:method name="add*" propagation="REQUIRED" />

           <tx:method name="update*" propagation="REQUIRED" />

           <tx:method name="delete*" propagation="REQUIRED" />

           <tx:method name="*" read-only="true" />

       </tx:attributes>

    </tx:advice>

<!-- 配置哪些类的方法需要进行事务管理,当前com.ssh2demo.li.Service下的所有类和子包的类的方法需要进行事务管理,还需要参考tx:advice的设置 -->

    <aop:config>

       <aop:pointcut id="allManagerMethod"

       expression="execution(* com.ssh2demo.li.Service..*.*(..))" />

       <aop:advisor advice-ref="txAdvice"

           pointcut-ref="allManagerMethod" />

    </aop:config>

 

在执行完com.ssh2demo.li.Service下的某个方法后,Session就关闭掉了。

如果应用中使用了OpenSessionInViewFilter所有打开的session会被保存在一个线程变量里。在线程退出前通过OpenSessionInViewFilter或者OpenSessionInViewInterceptor断开这些session

     也就是允许在每次的整个request的过程中使用同一个hibernate session,可以在这个request任何时期lazy loading数据。 这其实就是hibernate的延迟加载功能。

看看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的时候,会把获取回来的session flush mode 设为FlushMode.NEVER然后把该sessionFactory绑定到 TransactionSynchronizationManager,使request的整个过程都使用同一个session,在请求过后再接除该 sessionFactory的绑定,最后closeSessionIfNecessary根据该 session是否已和transaction绑定来决定是否关闭session在这个过程中,若HibernateTemplate 发现自当前session有不是readOnly transaction,就会获取到FlushMode.AUTO Session,使方法拥有写权限

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

 

对最上面项目的事务可以看出:

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

session.setFlushMode(FlushMode.AUTO);

session.save(user);

session.flush();

 Open Session In View看起来还不错,其实副作用不少

看回上面OpenSessionInViewFilter doFilterInternal方法代码,这个方法 实际上是被父类的doFilter调用的,因此,我们可以大约了解的 OpenSessionInViewFilter调用流程

1.request(请求)

2.open session并开始 transaction

3.controller

4.View(Jsp)

5.结束transaction  close session

一切看起来很正确,尤其是在本地开发测试的时候没出现问题,但试想下如果流程中的某一步被阻塞的话,那在这期间connection就一直被占用而不释 最有可能被阻塞的就是在写Jsp这步,一方面可能是页面内容大,response.write的时间长,另一方面可能是网速慢,服务器与用户间传输时 间久当大量这样的情况出现时,就有连接池连接不足,造成页面假死现象Open Session In View是个双刃剑,放在公网上内容多流量大的网站请慎用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值