今天在分析hibernate,自动生成hibernate配置文件的时候,会在dao层用到
getSession()方法来操作数据库记录,但是他还有个方法
getHibernateTemplate(),这两个方法究竟有什么区别呢?
1.使用getSession()方法你只要继承sessionFactory,而使用getHibernateTemplate()方法必须继承HibernateDaoSupport当然包括sessionFactory,这点区别都不是特别重要的,下面这些区别就很重要了
2.getSession()方法是没有经过spring包装的,spring会把最原始的session给你,在使用完之后必须自己调用相应的close方法,而且也不会对声明式事务进行相应的管理,一旦没有及时关闭连接,就会导致数据库连接池的连接数溢出,getHibernateTemplate()方法是经过spring封装的,例如添加相应的声明式事务管理,由spring管理相应的连接。
在实际的使用过程中发现的确getHibernateTemplate()比getSession()方法要好很多,但是有些方法在getHibernateTemplate()并没有提供,这时我们用HibernateCallback 回调的方法管理数据库.
例如如下代码:
具体参见hibernate的参考手册:
copy一段
getSession()这种直接使用Hibernate访问代码的好处在于它允许你在数据访问代码中抛出任何 checked exception,而 HibernateTemplate 却受限于回调中的unchecked exception。注意,你通常可以将这些应用程序的异常处理推迟到回调函数之后,这样,你依然可以正常使用 HibernateTemplate。一般来说,HibernateTemplate 类所提供的许多方法在许多情况下看上去更简单和便捷。
getSession()这个方法本身其实返回的是与当前事务绑定的Session对象, 在HibernateDaoSupport中使用,HibernateDaoSupport本身是不负责对这个Session对象进行关闭的,所以在其中有一个对应的releaseSession()方法,用于关闭Session。
但是一般使用Spring时,我们会采用HibernateTransactionManager进行事务管理,把事务配置在Service层。此时,它会帮助我们关闭与当前事务绑定的Session对象,这个可以参照HibernateTransactionManager类中的doCleanupAfterCompletion方法,它是一个抽象方法的实现。再追溯上去,会发现,在事务commit或者rollback的时候,会有一段finally代码,专门调用执行该方法的代码:
不过很多的web应用都会采用OpenSessionInView模式,也就是Session会被保持到View层。同样经过HibernateTransactionManager,为什么使用了OpenSessionInView模式以后,Session就不会被关闭呢?这是由于在获取当前线程绑定事务的时候,有一个判断,如果存在当前线程绑定的Session,会把当前事务对象的newSessionHolder值设置成false,从而跳过上面的代码中doCleanupAfterCompletion(status.getTransaction());的调用:
在Spring+Hibernate的集成环境里,如果DAO直接使用HibernateDaoSupport的getSession()方法获取 session进行数据操作而没有显式地关闭该session,那么程序表现为:每个session会打开一个connection,并且 connection会一直保持(因为没有显式地close).如果程序使用了c3p0连接池,则因为c3p0连接池默认最大连接数是15,程序会表现为当打开第15个连接时,程序处于停滞状态,等待从连接池获取新的连接.
在同样条件下,使用HibernateTemplate进行数据操作,就没有连接数持续增长的情况,程序结束时连接数归零.这印证了spring文档上所说:HibernateTemplate会对session进行了管理,能够确保Session实例的正确打开和关闭.
需要注意的是:在Spring环境里,即使我们使用Hibernate原生的API,比如这里所说的使用HibernateDaoSupport的getSession()方法得到Session进行数据操作(而不是使用Spring自己提供的API,比如HibernateTemplate),这些操作也依然会被纳入spring管理的事务中去.原因是通过getSession()方法得到Session是一个绑定到当前事务上的session.此处可参考:http://www.javaeye.com/topic/110801.这就是为什么Spring文档中提到的:You can implement DAOs basedon the plain Hibernate 3 API, while still being able to participate inSpring-managed transactions.
如果程序使用了OpenSessionInViewFilter或者OpenSessionInViewInterceptor那将是另外一种情形了.
简单总结:HibernateDaoSupport的getSession()得到的Session会参与Spring管理的事务中,但是不能自动的关闭.HibernateTemplate除能参与到Spring管理的事务中,还能够确保Session实例的正确打开和关闭.
1.使用getSession()方法你只要继承sessionFactory,而使用getHibernateTemplate()方法必须继承HibernateDaoSupport当然包括sessionFactory,这点区别都不是特别重要的,下面这些区别就很重要了
2.getSession()方法是没有经过spring包装的,spring会把最原始的session给你,在使用完之后必须自己调用相应的close方法,而且也不会对声明式事务进行相应的管理,一旦没有及时关闭连接,就会导致数据库连接池的连接数溢出,getHibernateTemplate()方法是经过spring封装的,例如添加相应的声明式事务管理,由spring管理相应的连接。
在实际的使用过程中发现的确getHibernateTemplate()比getSession()方法要好很多,但是有些方法在getHibernateTemplate()并没有提供,这时我们用HibernateCallback 回调的方法管理数据库.
例如如下代码:
/**
* 使用 hql 语句进行操作
* @param hql HSQL 查询语句(使用回调函数访问外部变量,必须是final的)
* @param offset 开始取数据的下标
* @param length 读取数据记录数
* @return List 结果集
*/
public List getListForPage ( final String hql , final int offset , final intlength ) {
List list = getHibernateTemplate().executeFind ( new HibernateCallback ( ) {
public Object doInHibernate ( Session session ) throws HibernateException,SQLException {
Query query = session.createQuery ( hql ) ;
query.setFirstResult ( offset ) ;
query.setMaxResults( length ) ;
List list = query.list ( ) ;
returnlist ;
}
}) ;
return list ;
}
总的来说
getHibernateTemplate()要优于getSession(),因为前者是后者的封装,楼主可以去看源码,这里面的各种操作,比如find、update等操作,就是回调的hibernate的方法。
具体参见hibernate的参考手册:
copy一段
getSession()这种直接使用Hibernate访问代码的好处在于它允许你在数据访问代码中抛出任何 checked exception,而 HibernateTemplate 却受限于回调中的unchecked exception。注意,你通常可以将这些应用程序的异常处理推迟到回调函数之后,这样,你依然可以正常使用 HibernateTemplate。一般来说,HibernateTemplate 类所提供的许多方法在许多情况下看上去更简单和便捷。
getSession()这个方法本身其实返回的是与当前事务绑定的Session对象, 在HibernateDaoSupport中使用,HibernateDaoSupport本身是不负责对这个Session对象进行关闭的,所以在其中有一个对应的releaseSession()方法,用于关闭Session。
但是一般使用Spring时,我们会采用HibernateTransactionManager进行事务管理,把事务配置在Service层。此时,它会帮助我们关闭与当前事务绑定的Session对象,这个可以参照HibernateTransactionManager类中的doCleanupAfterCompletion方法,它是一个抽象方法的实现。再追溯上去,会发现,在事务commit或者rollback的时候,会有一段finally代码,专门调用执行该方法的代码:
Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--> 1 finally {
cleanupAfterCompletion(status);
}
private void cleanupAfterCompletion(DefaultTransactionStatus status) {
status.setCompleted();
if (status.isNewSynchronization()) {
TransactionSynchronizationManager.clearSynchronization();
TransactionSynchronizationManager.setCurrentTransactionName(null);
TransactionSynchronizationManager.setCurrentTransactionReadOnly(false);
if (status.isNewTransaction()) {
TransactionSynchronizationManager.setActualTransactionActive(false);
}
}
if (status.isNewTransaction()) {
doCleanupAfterCompletion(status.getTransaction());
}
if (status.getSuspendedResources() != null) {
if (status.isDebug()) {
logger.debug("Resuming suspended transaction");
}
resume(status.getTransaction(), (SuspendedResourcesHolder) status.getSuspendedResources());
}
}
故而,只要参与了事务,HibernateTransactionManager会帮你正确关闭Session。
不过很多的web应用都会采用OpenSessionInView模式,也就是Session会被保持到View层。同样经过HibernateTransactionManager,为什么使用了OpenSessionInView模式以后,Session就不会被关闭呢?这是由于在获取当前线程绑定事务的时候,有一个判断,如果存在当前线程绑定的Session,会把当前事务对象的newSessionHolder值设置成false,从而跳过上面的代码中doCleanupAfterCompletion(status.getTransaction());的调用:
Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--> 1 protected Object doGetTransaction() {
HibernateTransactionObject txObject = new HibernateTransactionObject();
txObject.setSavepointAllowed(isNestedTransactionAllowed());
if (TransactionSynchronizationManager.hasResource(getSessionFactory())) {
SessionHolder sessionHolder =
(SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory());
if (logger.isDebugEnabled()) {
logger.debug("Found thread-bound Session [" +
SessionFactoryUtils.toString(sessionHolder.getSession()) + "] for Hibernate transaction");
}
txObject.setSessionHolder(sessionHolder, false);
if (getDataSource() != null) {
ConnectionHolder conHolder = (ConnectionHolder)
TransactionSynchronizationManager.getResource(getDataSource());
txObject.setConnectionHolder(conHolder);
}
}
return txObject;
}
综合一下,只要使用Spring的TransactionManager来管理事务,就可以放心在HibernateDaoSupport中使用getSession(),释放的工作会有Spring帮你完成。
在Spring+Hibernate的集成环境里,如果DAO直接使用HibernateDaoSupport的getSession()方法获取 session进行数据操作而没有显式地关闭该session,那么程序表现为:每个session会打开一个connection,并且 connection会一直保持(因为没有显式地close).如果程序使用了c3p0连接池,则因为c3p0连接池默认最大连接数是15,程序会表现为当打开第15个连接时,程序处于停滞状态,等待从连接池获取新的连接.
在同样条件下,使用HibernateTemplate进行数据操作,就没有连接数持续增长的情况,程序结束时连接数归零.这印证了spring文档上所说:HibernateTemplate会对session进行了管理,能够确保Session实例的正确打开和关闭.
需要注意的是:在Spring环境里,即使我们使用Hibernate原生的API,比如这里所说的使用HibernateDaoSupport的getSession()方法得到Session进行数据操作(而不是使用Spring自己提供的API,比如HibernateTemplate),这些操作也依然会被纳入spring管理的事务中去.原因是通过getSession()方法得到Session是一个绑定到当前事务上的session.此处可参考:http://www.javaeye.com/topic/110801.这就是为什么Spring文档中提到的:You can implement DAOs basedon the plain Hibernate 3 API, while still being able to participate inSpring-managed transactions.
如果程序使用了OpenSessionInViewFilter或者OpenSessionInViewInterceptor那将是另外一种情形了.
简单总结:HibernateDaoSupport的getSession()得到的Session会参与Spring管理的事务中,但是不能自动的关闭.HibernateTemplate除能参与到Spring管理的事务中,还能够确保Session实例的正确打开和关闭.