免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1006 | 回复: 0
打印 上一主题 下一主题

spring配置 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-01-31 11:13 |只看该作者 |倒序浏览
在没有使用Spring提供的Open Session In View情况下,
因需要在service(or Dao)层里把session关闭,
所以lazy loading 为true的话,要在应用层内把关系集
合都初始化,如 company.getEmployees(),
否则Hibernate抛session already closed Exception;   
Open Session In View提供了一种简便的方法,较好地解决了lazy loading问题.
它有两种配置方式OpenSessionInViewInterceptor和OpenSessionInViewFilter
(具体参看SpringSide),功能相同,只是一个在web.xml配置,
另一个在application.xml配置而已。
Open Session In View在request把session绑定到当前thread期间一直保持
hibernate session在open状态,使session在request的整个期间都可以使用,
如在View层里PO也可以lazy loading数据,如 ${ company.employees }。
当View 层逻辑完成后,才会通过Filter的doFilter方法或Interceptor的
postHandle方法自动关闭session。
OpenSessionInViewInterceptor配置
   
     
      
   
   
   
     
      
         
      
     
     
     
...     
  

...

OpenSessionInViewFilter配置

...   
     
hibernateFilter     
org.springframework.orm.hibernate3.support.OpenSessionInViewFilter     
     
   
      
singleSession      
true   
  

...   
     
hibernateFilter     
*.do   

...

很多人在使用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控制  
         
                  
                  
                        
                             
            PROPAGATION_REQUIRED,readOnly                 
            PROPAGATION_REQUIRED,readOnly                 
            PROPAGATION_REQUIRED,readOnly                 
            PROPAGATION_REQUIRED                 
            PROPAGATION_REQUIRED                 
            PROPAGATION_REQUIRED                 
            PROPAGATION_REQUIRED            
                     
                 
     
         
            
         
     

对于上例,则以save,add,update,remove开头的方法拥有可写的事务,
如果当前有某个方法,如命名为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调用流程:
   request(请求)->open session并开始transaction->controller->View(Jsp)->结束transaction并close session.
   
     一切看起来很正确,尤其是在本地开发测试的时候没出现问题,
     但试想下如果流程中的某一步被阻塞的话,
     那在这期间connection就一直被占用而不释放。最有可能被阻塞的就是在写Jsp这步,
     一方面可能是页面内容大,response.write的时间长,另一方面可能是网速慢,
     服务器与用户间传输时间久。当大量这样的情况出现时,就有连接池连接不足,
     造成页面假死现象。
Open Session In View是个双刃剑,放在公网上内容多流量大的网站请慎用。

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/26845/showart_474143.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP