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

酒馆儒生 2008-07-04 02:30:27
最近使用Struts1.3+Spring2.0+Hibernate3.2做了一个项目,最后测试时发现一个致命的错误,我的项目运行一段时间后,数据库直接down掉了。hibernate报了以下异常:
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中我使用
Query q = super.getSession().createQuery(hql);

语句可以正常执行,但是在多次使用该语句后数据库有很多连接仍然没有断开!这是导致异常的关键所在,spring不是管理了session吗?这是为什么呢?
通过继承HibernateDaoSupport我们有两个选择:
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回调接口。



...全文
1336 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
ubiquitious 2010-06-07
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 landor2004 的回复:]
解决办法1 this.releaseSession(session);
解决办法2 hibernate.connection.release_mode=auto
解决办法3 getSession(false);

不妨可以再测试一下
[/Quote]
auto好像不是hinerbante标准支持的东西吧
起码hibernate3中没有这个值,
只有after_statement
after_transaction
on_close
三个。
hero_shaoshuai 2008-12-22
  • 打赏
  • 举报
回复
收藏此贴
酒馆儒生 2008-07-06
  • 打赏
  • 举报
回复
6楼认识的很深刻啊,方法的确很多。
Landor2004 2008-07-05
  • 打赏
  • 举报
回复
解决办法1 this.releaseSession(session);
解决办法2 hibernate.connection.release_mode=auto
解决办法3 getSession(false);

不妨可以再测试一下
zhj92lxs 2008-07-05
  • 打赏
  • 举报
回复
支持
酒馆儒生 2008-07-04
  • 打赏
  • 举报
回复
回3楼,该测试是从网上参照而来。下面有参考网站
胡矣 2008-07-04
  • 打赏
  • 举报
回复
支持
Landor2004 2008-07-04
  • 打赏
  • 举报
回复
问一下,楼主的测试的for循环1000次,是在事务外面循环,还是在事务里面的
酒馆儒生 2008-07-04
  • 打赏
  • 举报
回复
另:可以设定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语句可以参考如下形式
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 ;
}


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

67,518

社区成员

发帖
与我相关
我的任务
社区描述
J2EE只是Java企业应用。我们需要一个跨J2SE/WEB/EJB的微容器,保护我们的业务核心组件(中间件),以延续它的生命力,而不是依赖J2SE/J2EE版本。
社区管理员
  • Java EE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧