HibernateDaoSupport Session封锁不了,连接数过多
getSession()这个方法本身其实返回的是与当前事务绑定的Session对象,在HibernateDaoSupport中使
用,HibernateDaoSupport本身是不负责对这个Session对象进行关闭的,所以在其中有一个对应的releaseSession()
方法,用于关闭Session。
但是一般使用Spring时,我们会采用HibernateTransactionManager进行事务管理,把事务配置在Service层。
此时,它会帮助我们关闭与当前事务绑定的Session对象,这个可以参照HibernateTransactionManager类中的
doCleanupAfterCompletion方法,它是一个抽象方法的实现。再追溯上去,会发现,在事务commit或者rollback的时候,
会有一段finally代码,专门调用执行该方法的代码:
- 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());
- }
- }
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());的调用:
- 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;
- }
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帮你完成。