升级到Hibernate 4.1和“臭名昭着”的HibernateTemplate

时间:2012-08-28 11:27:35

标签: java spring hibernate

我正在将我们的项目从Hibernate 3.0升级到Hibernate 4.1.6。 (我们目前正在使用春季3.1)

我在许多文章和HibernateTemplate文档中都读过,因为版本4.0不支持HibernateTemplate,我应该用调用sessionFactory.getCurrentSession()替换它的用法以获得会话。

由于这个项目是在较早版本的Hibernate中启动的,因此鼓励使用HibernateTemplate,我们目前在项目中有124个HibernateTemplate用法。我担心用sessionFactory.getCurrentSession()替换所有这些事件可能会在我们的项目中插入回归错误。此外,在非事务性上下文中有一些地方使用HibernateTemplate,其中没有“当前”会话。在这些情况下我该怎么办?打开一个新会话并自己处理(关闭)它?当我使用HibernateTemplate时,情况并非如此。

你有解决这些问题的好策略吗?

感谢。

相关阅读:

  1. Hibernate Vs. Spring - HibernateTemplate history
  2. Hibernate Core Migration Guide
  3. MIGRATING TO SPRING 3.1 AND HIBERNATE 4.1
  4. org.springframework.orm.hibernate3.HibernateTemplate

3 个答案:

答案 0 :(得分:11)

好的,这就是我实际做的,我不知道这是否是解决这个问题的最佳解决方案,但在我们的情况下,由于我在寻找最本地化的解决方案,对我来说似乎是最好的。

我已经扩展了springframework.orm.hibernate3.HibernateTemplate并创建了一个新的MyHibernateTemplate。新模板的主要作用是覆盖大多数hibernate3.HibernateTemplate最终导致的doExecute方法,并提供旧的SessionFactoryUtils提供的一些功能(如isSessionTransactional和applyTransactionTimeout)。

新的doExecute复制旧的逻辑,但不是SessionFactoryUtils.getNewSession来获取会话,它首先尝试查找一个打开的会话getSessionFactory()。getCurrentSession():

boolean newSessionOpened = false;
Session session;

if (enforceNewSession){
    session = SessionFactoryUtils.openSession(getSessionFactory());
    newSessionOpened = true;
} else {
    try {
        // look for an open session
        session = getSessionFactory().getCurrentSession();
    }
    catch (HibernateException ex) {
        try {
            // if there isn't an open session, open one yourself
            session = getSessionFactory().openSession();
            newSessionOpened = true;
        } catch (HibernateException e) {
            throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex);
        }
    }
}

// is the open session, is a session in a current transaction?
boolean existingTransaction = (!enforceNewSession &&
        (!isAllowCreate() || isSessionTransactional(session, getSessionFactory())));

您只需手动关闭此会话:

    finally {
    // if session was used in an existing transaction restore old settings
    if (existingTransaction) {
        //logger.debug("Not closing pre-bound Hibernate Session after HibernateTemplate");
        disableFilters(session);
        if (previousFlushMode != null) {
            session.setFlushMode(previousFlushMode);
        }
    }
    // if not and a new session was opened close it
    else {
        // Never use deferred close for an explicitly new Session.
        if (newSessionOpened) {
            SessionFactoryUtils.closeSession(session);
            //_log.info("Closing opened Hibernate session");
        }
    }

我正在尝试保持这个答案简短,但如果有任何问题我可以进一步详细说明这个问题。

答案 1 :(得分:2)

在文档中查看this section。它表示SessionFactory.getCurrentSession()是可插入的,并且有一个ThreadLocalSessionContext实现可以将“当前会话”保留在ThreadLocal而不是JTA事务中。 ThreadLocalSessionContext还将在从该Session创建的hibernate Transaction结束时关闭Session,因此您不必担心自己关闭Session

关于引入回归错误,升级库总是存在风险,尤其是当它作为hibernate应用程序的核心时。我可以给出的唯一建议是确保您的测试套件在升级之前具有良好的覆盖范围。毕竟,这是测试套件的工作 - 捕获回归错误。

答案 2 :(得分:0)

您还可以继续将HibernateTemplategetCurrentSession()一起使用,因为在许多情况下openSession()可能不是最佳选择,因为您需要自己关闭会话。 要使用currentSession,您可以添加以下内容来管理交易:

<prop key="hibernate.transaction.jta.platform">org.hibernate.engine.transaction.jta.platform.internal.JBossAppServerJtaPlatform</prop>

密钥的值将取决于您的AS。