为啥 Spring 在使用 Hibernate 3 时推迟关闭 Hibernate 会话
Posted
技术标签:
【中文标题】为啥 Spring 在使用 Hibernate 3 时推迟关闭 Hibernate 会话【英文标题】:Why does Spring defer to close a Hibernate session when use Hibernate 3为什么 Spring 在使用 Hibernate 3 时推迟关闭 Hibernate 会话 【发布时间】:2014-09-08 23:46:23 【问题描述】:背景:
我正在努力将我们产品中使用的 Hibernate 3 升级到 Hibernate 4。我们使用的 Spring 版本是 Spring 3.2,并且我们的代码大量使用 Spring 3.2 的 HibernateTemplate,而 org.springframework.orm 包不支持它。 hibernate4 了。作为第一步,我的任务是编写一个自定义版本的 HibernateTemplate,它使用 SessionFactory 来获取会话并删除 Hibernate 3 的所有依赖项。
问题:
当我阅读Spring 3.2的源码时,我注意到org.springframework.orm.hibernate3中的许多API在org.springframework.orm.hibernate4中被删除了.其中一种情况是 org.springframework.orm.hibernate3 包的 SessionFactoryUtils 中的 closeSessionOrRegisterDeferredClose 方法。
/**
* 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】:Hibernate 不会关闭会话。由呼叫者关闭会话。在这种情况下,调用者是 spring,这取决于您如何设置事务管理。
Spring 将在您的事务提交时关闭会话,或者在网络请求完成时(如果您配置正确)可选地关闭会话。
如果您没有任何事务管理设置,模板将在执行您传递给它的回调后立即关闭会话。
您在 HolderMap 中看到的是事务管理的一部分。
PS:HibernateTemplat
e 在 hibernate4 包中消失了,但是在 spring 4 中做了一个补偿。在 spring 3 中做 hibernate 4 的首选方式是使用SessionFactory.getCurrentSession()
,并让 spring 的事务支持管理打开和闭幕式。恕我直言,当他们这样做时,这是一个巨大的错误,但至少他们已经回溯了。
【讨论】:
也许你可以让答案不那么固执己见?例如,我认为您不应该再使用HibernateTemplate
,因为它真的不存在了(从Hiberate 3.0.1 开始,引入CurrentSessionContext
,模板或多或少是一种解决方法没有那个,它为 hibernate2 提供了有价值的异常翻译。现在所有这些都可以以更好的方式解决,从而导致更清洁的应用程序,即对 Spring API 的依赖更少。
我提出了 1 条意见。他们在 4 年春季将 HibernateTemplate 带回来的事实说明了人们想要它的事实。
它作为迁移选项被重新引入,也是之前 HibernateTemplate
的缩小版本,作为 sessionFactory.getCurrentSession
的简单包装器。
谢谢大家,我没有注意到 spring 4 带来了 HibernateTemplate。但是如果我坚持使用 Spring 3,是否有任何替代 spring hibernate 3 方法 closeSessionOrRegisterDeferredClose 的替代品?或者如果使用 Hibernate 4 会话,我不需要延迟关闭?以上是关于为啥 Spring 在使用 Hibernate 3 时推迟关闭 Hibernate 会话的主要内容,如果未能解决你的问题,请参考以下文章
JPA Spring Boot Hibernate Rest API:为啥Hibernate在插入之前会删除?
为啥我们的 Spring/Hibernate/JDBC/Websphere 系统中的连接过早关闭?
Spring上的DBCP和Hibernate,不会重新打开死连接,为啥?
spring security:为啥我们不能在@PreAuthorize 中访问 Hibernate 实体参数?
Spring Data JPA 是不是在内部使用 Hibernate 以及如果我不提供方言属性,为啥我的应用程序正在运行?