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);
    }  
    
可以看到OpenSessionInViewFilter在getSession的时候,会把获取回来的session的flush mode
设为FlushMode.NEVER。然后把该sessionFactory绑定到
TransactionSynchronizationManager,使request的整个过程都使用同一个session,在请求过后再接除该
sessionFactory的绑定,最后closeSessionIfNecessary根据该
session是否已和transaction绑定来决定是否关闭session。在这个过程中,若HibernateTemplate
发现自当前session有不是readOnly的transaction,就会获取到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);
     
    - 
    
    }
     
    - 
    
  } 
     
   
也即是,如果有不是readOnly的transaction就可以由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> 
    
     
    -     <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,如
         
    尽管Open Session In
    View看起来还不错,其实副作用不少。看回上面OpenSessionInViewFilter的doFilterInternal方法代码,这个方法
    实际上是被父类的doFilter调用的,因此,我们可以大约了解的OpenSessionInViewFilter调用流程:
    request(请求)->open
    session并开始transaction->controller->View(Jsp)->结束transaction并
    close session.
        
    一切看起来很正确,尤其是在本地开发测试的时候没出现问题,但试想下如果流程中的某一步被阻塞的话,那在这期间connection就一直被占用而不释
    放。最有可能被阻塞的就是在写Jsp这步,一方面可能是页面内容大,response.write的时间长,另一方面可能是网速慢,服务器与用户间传输时
    间久。当大量这样的情况出现时,就有连接池连接不足,造成页面假死现象。