1. 程式人生 > >使用hibernate資料庫連線不釋放的問題

使用hibernate資料庫連線不釋放的問題

最近同事遇到使用hibernate連線不釋放的問題,程式碼大概是下面這樣:

Query query = session.createQuery(hql);
for (int i = 0; i < values.length; i++) {
	query.setParameter(i, values[i]);
}
List result = query.setFirstResult(offset).setMaxResults(pageSize).list();

看了程式碼就知道原因了,明顯沒有關閉連線,所以才會出現連線不釋放的問題,應當手動呼叫session.close()

如果不想每次都要手動關閉連線,最好就不要使用上面的這種用法。簡單點的化可以藉助於HibernateDaoSupport來完成資料方法的執行,方法是你可以寫個DAO類繼承HibernateDaoSupport類就可以了。

為什麼這樣就不會有連線不釋放的問題?

看看HibernateDaoSupport原始碼,你會發現其方法基本上都是類似下面的結構:

getHibernateTemplate().execute(new HibernateCallback() {
	public Object doInHibernate(Session session) throws HibernateException {
		Query query = session.getNamedQuery(queryName);
		............
	}
});
可以看到實際上HibernateDaoSupport中的方法最終都是呼叫HibernateTemplate類的execute方法,而execute方法最終都會呼叫doExecute方法,下面是doExecute方法的原始碼,主要看看finally程式碼塊部分,就是在這裡關閉的連線
protected <T> T doExecute(HibernateCallback<T> action, boolean enforceNewSession, boolean enforceNativeSession)
			throws DataAccessException {

		Assert.notNull(action, "Callback object must not be null");

		Session session = (enforceNewSession ?
				SessionFactoryUtils.getNewSession(getSessionFactory(), getEntityInterceptor()) : getSession());
		boolean existingTransaction = (!enforceNewSession &&
				(!isAllowCreate() || SessionFactoryUtils.isSessionTransactional(session, getSessionFactory())));
		if (existingTransaction) {
			logger.debug("Found thread-bound Session for HibernateTemplate");
		}

		FlushMode previousFlushMode = null;
		try {
			previousFlushMode = applyFlushMode(session, existingTransaction);
			enableFilters(session);
			Session sessionToExpose =
					(enforceNativeSession || isExposeNativeSession() ? session : createSessionProxy(session));
			T result = action.doInHibernate(sessionToExpose);
			flushIfNecessary(session, existingTransaction);
			return result;
		}
		catch (HibernateException ex) {
			throw convertHibernateAccessException(ex);
		}
		catch (SQLException ex) {
			throw convertJdbcAccessException(ex);
		}
		catch (RuntimeException ex) {
			// Callback code threw application exception...
			throw ex;
		}
		finally {//在finally中關閉了session
			if (existingTransaction) {
				logger.debug("Not closing pre-bound Hibernate Session after HibernateTemplate");
				disableFilters(session);
				if (previousFlushMode != null) {
					session.setFlushMode(previousFlushMode);
				}
			}
			else {
				// Never use deferred close for an explicitly new Session.
				if (isAlwaysUseNewSession()) {
					SessionFactoryUtils.closeSession(session);
				}
				else {
					SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, getSessionFactory());
				}
			}
		}
	}

綜上,如果你是手動建立Query,那你要用完後必須要將session手動關閉。如果你是直接使用HibernateDaoSupport中的方法,那麼不需要手動關閉session。或者你呼叫HibernateTemplate的方法也沒有問題,類似getHibernateTemplate().execute(new HibernateCallback() {......})這樣。