现在的位置: 首页 > 综合 > 正文

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

2013年02月06日 ⁄ 综合 ⁄ 共 4397字 ⁄ 字号 评论关闭

转自:http://www.zzz8.com/thread-2387024-1-1.html

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

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回调接口。

(补充:之前项目中有遇到这个问题

bug如下:

org.springframework.transaction.CannotCreateTransactionException: Could not open Hibernate Session for transaction; nested exception is org.hibernate.exception.GenericJDBCException: Cannot open connection
org.hibernate.exception.GenericJDBCException: Cannot open connection

Caused by: java.sql.SQLException: org.logicalcobwebs.proxool.ProxoolException: ConnectionCount is 15. Maximum connection count of 15 cannot be exceeded.

,发现这篇文章分析的不错,所以就转载过来了;之前通过上网查资料,发现貌似OpenSessionInView模式这种貌似也可以控制session释放,但是网上说的方法我经过测试没有成功,网址如下:http://kewb.javaeye.com/blog/128726 按照配置去做,总是会报异常,配置成功的可以联系我,谢谢!)

另:可以设定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(){7

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 ;(

}; ~3

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

补充上回调函数调用存储过程方式:

public class ExecuteProceduresDaoImpl extends JdbcDaoSupport implements ExecuteProceduresDao {  

public Object Call_prLS_OrderByMemberOrNotMember(final String[] parm) {  
    String procedureSql = "{?=call prLS_OrderByMemberOrNotMember(?,?,?,?,?,?,?,?,?,?)}";  

        return (Object) getJdbcTemplate().execute(procedureSql, new CallableStatementCallback() {  

                    public Object doInCallableStatement(CallableStatement cs)  
                            throws SQLException, DataAccessException {  
                        int j = 2;  
                        cs.registerOutParameter(1, Types.INTEGER);  
                        if (parm != null) {  
                            for (int i = 0; i < parm.length; i++) {  
                                cs.setString(j, parm[i]);  
                                ++j;  
                            }  
                        }  
                        if (cs.execute()) {  
                            ResultSet rs = cs.getResultSet();  
                            while (rs.next()) {  
                                rs.getString(1);  
                                rs.getString(2);  
                                rs.getString(3);  
                            }  
                            return null;  
                        } else {  
                            return cs.getInt(1);  
                        }  
                    }  
                });  
    }  

}

抱歉!评论已关闭.