您的位置:首页 > 编程语言 > Java开发

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

2010-08-10 16:13 507 查看
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);

不妨可以再测试一下

____________________________________________________
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: