为什么在使用Hibernate 3时Spring要延迟关闭Hibernate会话

3

背景:

我正在升级我们产品中使用的Hibernate 3Hibernate 4。我们使用的Spring版本是Spring 3.2,我们的代码大量使用了Spring 3.2的HibernateTemplate,但是在org.springframework.orm.hibernate4包中不再支持它。作为第一步,我的任务是编写一个自定义版本的HibernateTemplate,它使用SessionFactory来获取session并移除所有Hibernate 3的依赖。

问题:

当我阅读Spring 3.2的源代码时,我注意到org.springframework.orm.hibernate3中的许多API在org.springframework.orm.hibernate4中被删除。其中一个例子是SessionFactoryUtils中的closeSessionOrRegisterDeferredClose方法,在org.springframework.orm.hibernate3包中。

/**
 * Close the given Session or register it for deferred close.
 * @param session the Hibernate Session to close
 * @param sessionFactory Hibernate SessionFactory that the Session was created with
 * (may be {@code null})
 * @see #initDeferredClose
 * @see #processDeferredClose
 */
static void closeSessionOrRegisterDeferredClose(Session session, SessionFactory sessionFactory) {
    Map<SessionFactory, Set<Session>> holderMap = deferredCloseHolder.get();
    if (holderMap != null && sessionFactory != null && holderMap.containsKey(sessionFactory)) {
        logger.debug("Registering Hibernate Session for deferred close");
        // Switch Session to FlushMode.MANUAL for remaining lifetime.
        session.setFlushMode(FlushMode.MANUAL);
        Set<Session> sessions = holderMap.get(sessionFactory);
        sessions.add(session);
    }
    else {
        closeSession(session);
    }
}

这个方法被 HibernateTemplate 类的 doExecute 方法调用(代码的最后一行)。
/**
 * Execute the action specified by the given action object within a Session.
 * @param action callback object that specifies the Hibernate action
 * @param enforceNewSession whether to enforce a new Session for this template
 * even if there is a pre-bound transactional Session
 * @param enforceNativeSession whether to enforce exposure of the native
 * Hibernate Session to callback code
 * @return a result object returned by the action, or {@code null}
 * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
 */
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 {
        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());
            }
        }
    }
}

org.springframework.orm.hibernate4包中仍然有SessionFactoryUtils类,但closeSessionOrRegisterDeferredClose方法已被删除。

问题:

我想知道:

1) 在哪些情况下Hibernate 3会推迟关闭会话?

2) 如果我在org.springframework.orm.hibernate4中使用Hibernate 4会话和类,是否仍需要进行延迟关闭?

1个回答

0
Hibernate不会关闭会话。关闭会话是调用者的责任。在这种情况下,调用者是Spring,这取决于您如何设置事务管理。
当您的事务提交时,Spring将关闭会话,或者(如果您正确配置)当Web请求完成时可选地关闭会话。
如果您没有设置任何事务管理,则模板将在执行传递给它的回调后立即关闭会话。
您在HolderMap中看到的内容是事务管理的一部分。
PS:HibernateTemplat在hibernate4包中消失了,但已经在spring 4中复出。在spring 3中进行hibernate 4的首选方法是使用SessionFactory.getCurrentSession(),并让spring的事务支持管理会话的打开和关闭。在我看来,当他们这样做时,这是一个巨大的错误,但至少他们已经改变了主意。

1
也许您可以让答案少一些个人观点?例如,我认为您不应再使用HibernateTemplate,因为它的应用情况已经不存在了(自从Hiberate 3.0.1引入CurrentSessionContext后,该模板基本上是为了弥补没有它而提供的解决方法,在hibernate2中,它提供了有价值的异常翻译。现在可以通过更好的方式解决所有这些问题,从而使应用程序更清洁,即减少对Spring API的依赖)。 - M. Deinum
我提出了一条意见。Spring 4中重新引入HibernateTemplate表明人们需要它。 - Matt
1
它被重新引入作为迁移选项,并且是先前的 HibernateTemplate的最小化版本,作为围绕sessionFactory.getCurrentSession的简单包装器。 - M. Deinum
谢谢大家,我没有注意到Spring 4将HibernateTemplate带回来了。但是如果我坚持使用Spring 3,是否有替代spring hibernate 3方法closeSessionOrRegisterDeferredClose?或者如果使用Hibernate 4会话,则不需要进行延迟关闭吗? - danny

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接