在使用Spring进行系统开发的时候,数据库连接一般都是配置在Spring的配置文件中,并且由Spring来管理的。在利用Spring + Hibernate进行开发时也是如此。下面是一个简单的Spring + Hibernate Dao的例子: 程序代码

public class DaoReal extends HibernateDaoSupport implements Dao { 

   public List<User> getAll() { 

     return super.getHibernateTemplate().find("from User"); 

   } 

 } 


   在上面的这个例子中,我们并没有关闭Session,但程序并没有任何问题,那是因为Spring已经帮我们关闭了。那么再看一个例子: 


 程序代码 

public class DaoReal extends HibernateDaoSupport implements Dao { 

   public List<User> getAll() { 

 return super.getSession().createQuery("from User").list(); 

   } 

 } 


   这个例子会不会有问题呢?的确,上面的例子中隐藏了一个问题,数据库连接并没有被关闭,在我们的印象中这件事似乎应该是Spring的。程序执行后,好像也没有什么问题,但是连续执行该语句n次(n<=最大连接数,如果没有指定最大连接数,那么默认为10次)后,系统处于等待状态,不会继续执行了,控制台上并没有输出任何信息。打开log文件,发现系统抛出java.lang.IllegalStateException: Pool not open的异常,无法打开连接。这说明系统连接池中所有的连接都在使用中。那么我们手动关闭Session后,应该就没有问题了吧!是这样吗?修改我们的例子,如下: 


 程序代码 

public class DaoReal extends HibernateDaoSupport implements Dao { 

   public List<User> getAll() { 

     Session s = super.getSession(); 

     try { 

       return s.createQuery("from User").list(); 

     } finally { 

       s.close(); 

     } 

   } 

 } 


   执行n遍后依然停止响应。问题出在哪里呢?其实Spring的Session总是与某个线程绑定的,而这个线程往往就是承载Servlet或Jsp的那个线程,也就是说,它的生命周期scope是request的。在上面的例子中,我们利用getSession强制获得了Hibernate的Session,这个Session可能是当前事务中之前使用过的,或者可能是一个新的,并不在当前事务中,Spring只对当前事务中的Session进行关闭。 


   要解决这个问题,方法有很多。可以使用我们之前讲到过的getHibernateTemplate().find()。也可以设定HibernateTemplate的AllowCreate为True,并在finally中关闭Session。也可以将true作为参数传递到super.getSession(..)方法中取得Session。这里的true表示允许创建。 


//--------------------------------------------------------- 

[color=red]另外一篇文章 说的更详细点[/color] 

多运行几次数据库连接就满了程序无法继续执行下去。经测试是使用SPRING的getSession()方法获得的连接没有关闭连接。在这里讨论一下SPRING SESSION管理机制。 


先看代码: 


public class ItemDAOImpl extends HibernateDaoSupport implements ItemDAO { 



public List queryAll() throws Exception { 


// TODO Auto-generated method stub 


Session session=super.getSession(true); 


String hql="from Item as i"; 


List l=super.getSession().createQuery(hql).list(); 


return l; 


} 


}\ 


其实上面的代码隐藏了一个问题,数据库连接并没有被关闭,所以一直出现以上的问题。 


我的解决方法还是静态模式: 


public Session session; 

public Session getcurrentSession() 

{ 

if(session==null) 

session=this.getSession(); 

return session; 

} 


Iterator it =this.getcurrentSession().createQuery(hql).list().iterator(); 


暂时可以解决此问题。。更好的办法还在网上找到一篇文章和大家共享: 


这里提供三个解决方案 方案一: 


getHibernateTemplate().find(hql); 


虽然没有手动关闭数据库连接,但spring已经帮我们关闭了。 


方案二:(经测试,此方案比较有效) 


设定HibernateTemplate的AllowCreate为True 


在spring API 的HibernateDaoSupport中 


protected net.sf.hibernate.Session getSession(boolean allowCreate) 


Get a Hibernate Session, either from the current transaction or a new one. 


public class ItemDAOImpl extends HibernateDaoSupport implements ItemDAO { 



public List queryAll() throws Exception { 


// TODO Auto-generated method stub 


Session session=super.getSession(true); 


String hql="from Item as i"; 


List l=session.createQuery(hql).list(); 


try{ 


return l; 


}finally{ 


session.close(); 


} 


} 


} 


Spring API: 

geSession()是org.springframework.orm.hibernate3.support.HibernateDaoSupport 中的一个方法, 

它可以从当前事务或者一个新的事务获得一个hibernate session. 

通常使用releaseSession(org.hibernate.Session)方法与getSession()配合。 

如果没有绑定线程,releaseSession关闭由这个DAO的SessionFactory创建的Hibernate Session。  

修改后的代码如下: 



public class ItemDAOImpl extends HibernateDaoSupport implements ItemDAO { 


public List queryAll() throws Exception { 


// TODO Auto-generated method stub 


Session session = super.getSession(); 


String hql = "from Item as i"; 


List l = session.createQuery(hql).list(); 


releaseSession(session); 



} 


}

困扰了几天的问题终于解决了,项目搁浅了好几天了,就是对spring对session的管理不清楚。 关于getSession()下面有更多讨论: http://www.javaeye.com/topic/24309 http://www.javaeye.com/post/140793 总的讨论热点就是getSession()要不要手动关闭的问题。 观点: 1.使用getSession()返回session有两种情况。 a.当前线程有存在session,就直接返回。 b.当前线程中不存在session就重新创建一个。 如果spring配置了事务,那么session就不必关闭,在事务完成之后将被自动关闭。如果没有参与事务那就要调用session.close()关闭。 2.getSession()拿到的Session无论是否参与事务,Spring都不负责关闭,除非使用OpenSessionInView模式。