我们再用spring管理hibernate的时候, 我们会继承HibernateDaoSupport 或者HibernateTemplate类.
我们不知道这两个类之间有什么关系. 也没有去关闭session. 让我很是心不安,他可没有关闭session呀.如果..真的是后果不堪设想.百度了好久, 谷歌了好多. 都没有一个像样的说法. 说spring中HibernateDaoSupport会自己关闭session.
眼见为实.于是乎决定查看spring源码一探究竟.
先打开HibernateDaoSupoprt看看.
public abstract class HibernateDaoSupport extends DaoSupport {
private HibernateTemplate hibernateTemplate;
public final void setSessionFactory(SessionFactory sessionFactory) {
this.hibernateTemplate = createHibernateTemplate(sessionFactory);
}
protected HibernateTemplate createHibernateTemplate(SessionFactory sessionFactory) {
return new HibernateTemplate(sessionFactory);
}
public final SessionFactory getSessionFactory() {
return (this.hibernateTemplate != null ? this.hibernateTemplate.getSessionFactory() : null);
}
public final void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
this.hibernateTemplate = hibernateTemplate;
}
public final HibernateTemplate getHibernateTemplate() {
return hibernateTemplate;
}
protected final void checkDaoConfig() {
if (this.hibernateTemplate == null) {
throw new IllegalArgumentException("sessionFactory or hibernateTemplate is required");
}
}
protected final Session getSession()
throws DataAccessResourceFailureException, IllegalStateException {
return getSession(this.hibernateTemplate.isAllowCreate());
}
protected final Session getSession(boolean allowCreate)
throws DataAccessResourceFailureException, IllegalStateException {
return (!allowCreate ?
SessionFactoryUtils.getSession(getSessionFactory(), false) :
SessionFactoryUtils.getSession(
getSessionFactory(),
this.hibernateTemplate.getEntityInterceptor(),
this.hibernateTemplate.getJdbcExceptionTranslator()));
}
protected final DataAccessException convertHibernateAccessException(HibernateException ex) {
return this.hibernateTemplate.convertHibernateAccessException(ex);
}
protected final void releaseSession(Session session) {
SessionFactoryUtils.releaseSession(session, getSessionFactory());
}
在这里我们会注意到一个private 对象. 那就是HibernateTemplate. 这里面也有一个HibernateTemplate的set. get.
哦: 原来如此.呵呵,很白痴的事.
比如说. BaseDao extends HibernateDaoSupport 我们会super.getHibernateTemplate.find(hql);
super.getHibernateTemplate.save(obj);
和BaseDao extends HibernateTemplate 中super.find(hql)和super.save(obj);是等效的. 原来没有思考害的我改了一个多小时. 汗..
下面我们来看看HibernateTemplate是怎么样来操作session的呢.
照样我们贴出源代码. 由于这个类代码较多. 我只贴出来几个代表性的属性和方法, 供大家参考.
public class HibernateTemplate extends HibernateAccessor implements HibernateOperations {
private boolean allowCreate = true;
private boolean alwaysUseNewSession = false;
private boolean exposeNativeSession = false;
private boolean checkWriteOperations = true;
private boolean cacheQueries = false;
private String queryCacheRegion;
private int fetchSize = 0;
private int maxResults = 0;
public void ......();
} 一系列的方法.
下面我们看看save()方法.
public Serializable save(final Object entity) throws DataAccessException {
return (Serializable) execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
checkWriteOperationAllowed(session);
return session.save(entity);
}
}, true);
}
我们再看看update(), merge(), find()等方法的源码.
//update 方法
public void update(Object entity) throws DataAccessException {
update(entity, null);
}
public void update(final Object entity, final LockMode lockMode) throws DataAccessException {
execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
checkWriteOperationAllowed(session);
session.update(entity);
if (lockMode != null) {
session.lock(entity, lockMode);
}
return null;
}
}, true);
}
//merge()
public Object merge(final Object entity) throws DataAccessException {
return execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
checkWriteOperationAllowed(session);
return session.merge(entity);
}
}, true);
}
//find()
public List find(String queryString) throws DataAccessException {
return find(queryString, (Object[]) null);
}
public List find(String queryString, Object value) throws DataAccessException {
return find(queryString, new Object[] {value});
}
public List find(final String queryString, final Object[] values) throws DataAccessException {
return (List) execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
Query queryObject = session.createQuery(queryString);
prepareQuery(queryObject);
if (values != null) {
for (int i = 0; i < values.length; i++) {
queryObject.setParameter(i, values[i]);
}
}
return queryObject.list();
}
}, true);
}
细心的朋友们可能发现了. 他们无一例外的都调用了一个叫做execute()的方法. 对了. 我们再看看execute的面目.到底他干了一件什么样的事情呢?]
public Object execute(HibernateCallback action, boolean exposeNativeSession) throws DataAccessException {
Session session = getSession();
boolean existingTransaction = 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 = (exposeNativeSession ? session : createSessionProxy(session));
Object 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 {
if (existingTransaction) {
logger.debug("Not closing pre-bound Hibernate Session after HibernateTemplate");
disableFilters(session);
if (previousFlushMode != null) {
session.setFlushMode(previousFlushMode);
}
}
else {
SessionFactoryUtils.releaseSession(session, getSessionFactory());
}
}
}
抛掉其他的不管. finally中我们可以看到. 如果existingTransaction 他会
logger.debug("Not closing pre-bound Hibernate Session after HibernateTemplate");
disableFilters(session);
if (previousFlushMode != null) {
session.setFlushMode(previousFlushMode);
}
他并没有立即关闭session.
否则
SessionFactoryUtils.releaseSession(session, getSessionFactory());
他释放掉了session . 真的close()了吗?
我们在看看sessionFactoryUtil.的releaseSession()
public static void releaseSession(Session session, SessionFactory sessionFactory) {
if (session == null) {
return;
}
// Only close non-transactional Sessions.
if (!isSessionTransactional(session, sessionFactory)) {
closeSessionOrRegisterDeferredClose(session, sessionFactory);
}
}
static void closeSessionOrRegisterDeferredClose(Session session, SessionFactory sessionFactory) {
Map holderMap = (Map) deferredCloseHolder.get();
if (holderMap != null && sessionFactory != null && holderMap.containsKey(sessionFactory)) {
logger.debug("Registering Hibernate Session for deferred close");
Set sessions = (Set) holderMap.get(sessionFactory);
sessions.add(session);
if (!session.isConnected()) {
// We're running against Hibernate 3.1 RC1, where Hibernate will
// automatically disconnect the Session after a transaction.
// We'll reconnect it here, as the Session is likely gonna be
// used for lazy loading during an "open session in view" pase.
session.reconnect();
}
}
else {
doClose(session);
}
}
private static void doClose(Session session) {
if (session != null) {
logger.debug("Closing Hibernate Session");
try {
session.close();
}
catch (HibernateException ex) {
logger.error("Could not close Hibernate Session", ex);
}
catch (RuntimeException ex) {
logger.error("Unexpected exception on closing Hibernate Session", ex);
}
}
}
呵呵, 現在終於心安裡德的去睡覺了. 因为他真的关了.