探讨Spring与Hibernate的整合所遇到的管理Session的问题

36 篇文章 0 订阅
15 篇文章 0 订阅

http://topic.csdn.net/u/20080704/14/bb2751bf-cd0a-4025-9e66-18f9031b1361.html

 

最近使用Struts1.3+Spring2.0+Hibernate3.2做了一个项目,最后测试时发现一个致命的错误,我的项目运行一段时间后,数据库直接down掉了。hibernate报了以下异常:

Java code
   
   
2008 - 06 - 30 19 : 00 : 02 , 250 WARN [com.mchange.v2.resourcepool.BasicResourcePool] - com.mchange.v2.resourcepool.BasicResourcePool$AcquireTask@b27de5 -- Acquisition Attempt Failed !!! Clearing pending acquires. While trying to acquire a needed new resource, we failed to succeed more than the maximum number of allowed acquisition attempts ( 30 ). 2008 - 06 - 30 19 : 00 : 02 , 312 WARN [org.hibernate.util.JDBCExceptionReporter] - SQL Error: 0 , SQLState: null 2008 - 06 - 30 19 : 00 : 02 , 312 ERROR [org.hibernate.util.JDBCExceptionReporter] - Connections could not be acquired from the underlying database ! 2008 - 06 - 30 19 : 00 : 02 , 328 WARN [org.hibernate.util.JDBCExceptionReporter] - SQL Error: 0 , SQLState: null 2008 - 06 - 30 19 : 00 : 02 , 328 ERROR [org.hibernate.util.JDBCExceptionReporter] - Connections could not be acquired from the underlying database ! org.hibernate.exception.GenericJDBCException: Cannot open connection at org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java: 103 ) at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java: 91 ) at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java: 43 ) at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java: 29 ) at org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java: 420 ) at org.hibernate.jdbc.ConnectionManager.getConnection(ConnectionManager.java: 144 ) at org.hibernate.jdbc.AbstractBatcher.prepareQueryStatement(AbstractBatcher.java: 105 ) at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java: 1561 ) at org.hibernate.loader.Loader.doQuery(Loader.java: 661 ) at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java: 224 ) at org.hibernate.loader.Loader.doList(Loader.java: 2145 ) at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java: 2029 ) at org.hibernate.loader.Loader.list(Loader.java: 2024 ) at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java: 375 ) at org.hibernate.hql.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java: 308 ) at org.hibernate.engine.query.HQLQueryPlan.performList(HQLQueryPlan.java: 153 ) at org.hibernate.impl.SessionImpl.list(SessionImpl.java: 1106 ) at org.hibernate.impl.QueryImpl.list(QueryImpl.java: 79 ) at cn.gcy.cyzd.impl.ItemDAOImpl.queryAll(ItemDAOImpl.java: 15 ) at cn.gcy.cyzd.struts.action.IndexAction.list(IndexAction.java: 54 ) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at org.apache.struts.actions.DispatchAction.dispatchMethod(DispatchAction.java: 269 ) at org.apache.struts.actions.DispatchAction.execute(DispatchAction.java: 170 ) at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java: 425 ) at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java: 228 ) at org.apache.struts.action.ActionServlet.process(ActionServlet.java: 1913 ) at org.apache.struts.action.ActionServlet.doGet(ActionServlet.java: 449 ) at javax.servlet.http.HttpServlet.service(HttpServlet.java: 690 ) at javax.servlet.http.HttpServlet.service(HttpServlet.java: 803 ) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java: 290 ) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java: 206 ) at cn.gcy.cyzd.filter.EncodingFilter.doFilter(EncodingFilter.java: 22 ) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java: 235 ) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java: 206 ) at org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java: 198 ) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java: 75 ) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java: 235 ) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java: 206 ) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java: 233 ) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java: 175 ) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java: 128 ) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java: 102 ) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java: 109 ) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java: 286 ) at org.apache.coyote.http11.Http11AprProcessor.process(Http11AprProcessor.java: 856 ) at org.apache.coyote.http11.Http11AprProtocol$Http11ConnectionHandler.process(Http11AprProtocol.java: 565 ) at org.apache.tomcat.util.net.AprEndpoint$Worker.run(AprEndpoint.java: 1509 ) at java.lang.Thread.run(Unknown Source) Caused by: java.sql.SQLException: Connections could not be acquired from the underlying database ! at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java: 104 ) at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java: 236 ) at com.mchange.v2.c3p0.PoolBackedDataSource.getConnection(PoolBackedDataSource.java: 94 ) at com.mchange.v2.c3p0.ComboPooledDataSource.getConnection(ComboPooledDataSource.java: 521 ) at org.springframework.orm.hibernate3.LocalDataSourceConnectionProvider.getConnection(LocalDataSourceConnectionProvider.java: 81 ) at org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java: 417 ) ... 46 more Caused by: com.mchange.v2.resourcepool.CannotAcquireResourceException: A ResourcePool could not acquire a resource from its primary factory or source. at com.mchange.v2.resourcepool.BasicResourcePool.awaitAcquire(BasicResourcePool.java: 970 ) at com.mchange.v2.resourcepool.BasicResourcePool.checkoutResource(BasicResourcePool.java: 208 ) at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java: 232 ) ... 50 more 2008 - 06 - 30 19 : 00 : 05 , 093 WARN [com.mchange.v2.resourcepool.BasicResourcePool] - com.mchange.v2.resourcepool.BasicResourcePool$AcquireTask@4c03d4 -- Acquisition Attempt Failed !!! Clearing pending acquires. While trying to acquire a needed new resource, we failed to succeed more than the maximum number of allowed acquisition attempts ( 30 ).


这个错误郁闷了我很久,通过大家的帮助还有网络的大量资源我终于找到了其中的原因。首先说说我的daoimpl的写法
在daoimpl中我使用
Java code
   
   
Query q = super .getSession().createQuery(hql);

语句可以正常执行,但是在多次使用该语句后数据库有很多连接仍然没有断开!这是导致异常的关键所在,spring不是管理了session吗?这是为什么呢?
通过继承HibernateDaoSupport我们有两个选择:
 
Java code
   
   
getSession().createQuery( " from Users " ); getHibernateTemplate().find( " FROM Users);


网上找了找资料都是推荐用getHibernateTemplate,原因说的不是很清楚。

于是我做了如下测试:

分别循环调用getSession().createQuery("from Users");getHibernateTemplate().find( "FROM Users);
1000次
结果getSession()很快就包无法建立连接了。而getHibernateTemplate屁事没有可以跑完。

通过后台观察,使用getSession会在数据库中留下很多SQL*Net message from client的连接,终止测试后连接自动释放。
而getHibernateTemplate则从头到尾都使用一个连接。

难道是getSession()不会自动释放连接?

于是我又分别循环调用getSession().createQuery("from Users");getHibernateTemplate().find( "FROM Users);
5次
发现当前端程序一结束,getSession的5个连接立刻就释放了。结合前面1000次时终止测试后连接自动释放,可以说明getSession()是会自动释放连接的。

结论:
1、getSession()和getHibernateTemplate都可以自动释放连接(当然你的配置要正确),但是在一个线程内getSession会get很多个session(就是开很多个会话、连接),很可能导致数据库连接超过上限。所以推荐使用getHibernateTemplate。

2、如果有些语句无法用getHibernateTemplate实现,可以使用getHibernateTemplate.execute使用HibernateCallback回调接口。

 

另:可以设定HibernateTemplate的AllowCreate为True,并在finally中关闭Session。也可以将true作为参数传递到super.getSession(..)方法中取得Session。这样也可以,就是麻烦点。
参见:
http://springframework.org/docs/api/org/springframework/orm/hibernate3/HibernateTemplate.html
http://www.mxjava.com/blog/article.asp?id=246
参考资料:http://blog.sina.com.cn/s/blog_50e4caf70100a1nx.html

于是,如果我们一定要书写hql语句可以参考如下形式

Java code
   
   
public PageUtil getLog( final Long userid, final Integer page) { String counthql = " select count(mod) from Blog mod where mod.userinfo.userid=? " ; Integer count = (Integer)getHibernateTemplate().find(counthql, userid).get( 0 ); final PageUtil pu = new PageUtil(); // 分页包装类 pu.setCount(count); pu.setPage(page); pu.setMaxPagesbyCount(count); List li = getHibernateTemplate().executeFind( new HibernateCallback(){ public Object doInHibernate(Session session) throws HibernateException, SQLException { String hql = " from Blog mod left join fetch mod.userinfo where mod.userinfo.userid=? order by mod.logid desc " ; Query query = session.createQuery(hql); query.setParameter( 0 , userid); query.setMaxResults(pu.getMaxResults()); query.setFirstResult(pu.getFirstResult()); return query.list(); } }); pu.setResults(li); return pu ; }



只有这样做了以后才能确保数据库的连接能够尽早被释放,项目不至于崩溃。

 

____________________________________________________

 

解决办法1 this.releaseSession(session);
解决办法2 hibernate.connection.release_mode=auto
解决办法3 getSession(false);

不妨可以再测试一下

____________________________________________________

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值