【问题标题】:Upgrading to Hibernate 4.1 and the "infamous" HibernateTemplate升级到 Hibernate 4.1 和“臭名昭著”的 HibernateTemplate
【发布时间】:2012-08-22 21:41:47
【问题描述】:

我正在将我们的项目从 Hibernate 3.0 升级到 Hibernate 4.1.6。 (而且我们目前使用的是spring 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

【问题讨论】:

标签: java spring hibernate


【解决方案1】:

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

我扩展了 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");
        }
    }

我试图让这个答案简短,但如果有任何问题,我可以进一步详细说明这个问题。

【讨论】:

  • 这是一个棘手的问题,因为 HibernateTemplate 和朋友的功能非常多。在找到这篇文章之前,我已经走了与您描述的大致相同的道路,但是克隆了 HibernateTemplate 而不是扩展它。我不确定这是最好的策略。我需要考虑很多功能,所以我担心生成的代码的稳定性。我知道这对你来说已经是古老的历史了,但你能分享更多关于你的策略,以及它是如何为你成功的吗?
【解决方案2】:

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

关于引入回归错误,升级库总是有风险的,尤其是当它是你的应用程序的核心时,如休眠。我能给出的唯一建议是确保您的测试套件在升级之前具有良好的覆盖率。毕竟,这是您的测试套件的工作——捕捉回归错误。

【讨论】:

    【解决方案3】:

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

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

    键的值取决于你的 AS。

    【讨论】:

      猜你喜欢
      • 2015-03-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-18
      • 1970-01-01
      • 2012-01-09
      • 2011-04-14
      相关资源
      最近更新 更多