SessionFactoryUtils

SessionFactoryUtils支持JTATransactionManager和HibernateTransactionManager;被Spring内部HibernateTemplate或HibernateInterceptor使用,同时可由应用代码调用。它提供了事务或非事务性Session获取,释放,Hibernate异常转换,事务超时等功能。下面介绍主要方法

doGetSession

如果SessionHolder中存在Session,则检测sessionHolder是否事务同步,否则注册同步;
否则创建新的Session,注册同步并绑定线程
同步
Spring同步激活状态下,使用Spring同步,同时设置FlushMode;
否则Hibernate的javax.transaction.TransactionManager检测到激活的JTA事务,则使用JTA同步,同时设置FlushMode;这种情况下sessionMap放置key=javax.transaction.Transaction,value=Session
否则不使用同步
FlushMode
修改非只读事务(由definition指定)的FlushMode模式由FlushMode.Manual为FlushMode.AUTO,以至于事务提交时可Flush;待事务处理完成之后再回复。

/**
* Get a Hibernate Session for the given SessionFactory. Is aware of and will
* return any existing corresponding Session bound to the current thread, for
* example when using HibernateTransactionManager. Will create a new Session
* otherwise, if "allowCreate" is <code>true</code>.
* <p>Same as <code>getSession</code>, but throwing the original HibernateException.
* @param sessionFactory Hibernate SessionFactory to create the session with
* @param entityInterceptor Hibernate entity interceptor, or <code>null</code> if none
* @param jdbcExceptionTranslator SQLExcepionTranslator to use for flushing the
* Session on transaction synchronization (can be <code>null</code>)
* @param allowCreate if a non-transactional Session should be created when no
* transactional Session can be found for the current thread
* @return the Hibernate Session
* @throws HibernateException if the Session couldn't be created
* @throws IllegalStateException if no thread-bound Session found and
* "allowCreate" is <code>false</code>
*/
private static Session doGetSession(
SessionFactory sessionFactory, Interceptor entityInterceptor,
SQLExceptionTranslator jdbcExceptionTranslator, boolean allowCreate)
throws HibernateException, IllegalStateException {

Assert.notNull(sessionFactory, "No SessionFactory specified");

SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
if (sessionHolder != null && !sessionHolder.isEmpty()) {
// pre-bound Hibernate Session
Session session = null;
if (TransactionSynchronizationManager.isSynchronizationActive() &&
sessionHolder.doesNotHoldNonDefaultSession()) {
// Spring transaction management is active ->
// register pre-bound Session with it for transactional flushing.
session = sessionHolder.getValidatedSession();
if (session != null && !sessionHolder.isSynchronizedWithTransaction()) {
logger.debug("Registering Spring transaction synchronization for existing Hibernate Session");
TransactionSynchronizationManager.registerSynchronization(
new SpringSessionSynchronization(sessionHolder, sessionFactory, jdbcExceptionTranslator, false));
sessionHolder.setSynchronizedWithTransaction(true);
// Switch to FlushMode.AUTO, as we have to assume a thread-bound Session
// with FlushMode.NEVER, which needs to allow flushing within the transaction.
FlushMode flushMode = session.getFlushMode();
if (flushMode.lessThan(FlushMode.COMMIT) &&
!TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
session.setFlushMode(FlushMode.AUTO);
sessionHolder.setPreviousFlushMode(flushMode);
}
}
}
else {
// No Spring transaction management active -> try JTA transaction synchronization.
session = getJtaSynchronizedSession(sessionHolder, sessionFactory, jdbcExceptionTranslator);
}
if (session != null) {
return session;
}
}

logger.debug("Opening Hibernate Session");
Session session = (entityInterceptor != null ?
sessionFactory.openSession(entityInterceptor) : sessionFactory.openSession());

// Use same Session for further Hibernate actions within the transaction.
// Thread object will get removed by synchronization at transaction completion.
if (TransactionSynchronizationManager.isSynchronizationActive()) {
// We're within a Spring-managed transaction, possibly from JtaTransactionManager.
logger.debug("Registering Spring transaction synchronization for new Hibernate Session");
SessionHolder holderToUse = sessionHolder;
if (holderToUse == null) {
holderToUse = new SessionHolder(session);
}
else {
holderToUse.addSession(session);
}
if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
session.setFlushMode(FlushMode.NEVER);
}
TransactionSynchronizationManager.registerSynchronization(
new SpringSessionSynchronization(holderToUse, sessionFactory, jdbcExceptionTranslator, true));
holderToUse.setSynchronizedWithTransaction(true);
if (holderToUse != sessionHolder) {
TransactionSynchronizationManager.bindResource(sessionFactory, holderToUse);
}
}
else {
// No Spring transaction management active -> try JTA transaction synchronization.
registerJtaSynchronization(session, sessionFactory, jdbcExceptionTranslator, sessionHolder);
}

// Check whether we are allowed to return the Session.
if (!allowCreate && !isSessionTransactional(session, sessionFactory)) {
closeSession(session);
throw new IllegalStateException("No Hibernate Session bound to thread, " +
"and configuration does not allow creation of non-transactional one here");
}

return session;
}

/**
* Retrieve a Session from the given SessionHolder, potentially from a
* JTA transaction synchronization.
* @param sessionHolder the SessionHolder to check
* @param sessionFactory the SessionFactory to get the JTA TransactionManager from
* @param jdbcExceptionTranslator SQLExcepionTranslator to use for flushing the
* Session on transaction synchronization (can be <code>null</code>)
* @return the associated Session, if any
* @throws DataAccessResourceFailureException if the Session couldn't be created
*/
private static Session getJtaSynchronizedSession(
SessionHolder sessionHolder, SessionFactory sessionFactory,
SQLExceptionTranslator jdbcExceptionTranslator) throws DataAccessResourceFailureException {

// JTA synchronization is only possible with a javax.transaction.TransactionManager.
// We'll check the Hibernate SessionFactory: If a TransactionManagerLookup is specified
// in Hibernate configuration, it will contain a TransactionManager reference.
TransactionManager jtaTm = getJtaTransactionManager(sessionFactory, sessionHolder.getAnySession());
if (jtaTm != null) {
// Check whether JTA transaction management is active ->
// fetch pre-bound Session for the current JTA transaction, if any.
// (just necessary for JTA transaction suspension, with an individual
// Hibernate Session per currently active/suspended transaction)
try {
// Look for transaction-specific Session.
Transaction jtaTx = jtaTm.getTransaction();
if (jtaTx != null) {
int jtaStatus = jtaTx.getStatus();
if (jtaStatus == Status.STATUS_ACTIVE || jtaStatus == Status.STATUS_MARKED_ROLLBACK) {
Session session = sessionHolder.getValidatedSession(jtaTx);
if (session == null && !sessionHolder.isSynchronizedWithTransaction()) {
// No transaction-specific Session found: If not already marked as
// synchronized with transaction, register the default thread-bound
// Session as JTA-transactional. If there is no default Session,
// we're a new inner JTA transaction with an outer one being suspended:
// In that case, we'll return null to trigger opening of a new Session.
session = sessionHolder.getValidatedSession();
if (session != null) {
logger.debug("Registering JTA transaction synchronization for existing Hibernate Session");
sessionHolder.addSession(jtaTx, session);
jtaTx.registerSynchronization(
new SpringJtaSynchronizationAdapter(
new SpringSessionSynchronization(sessionHolder, sessionFactory, jdbcExceptionTranslator, false),
jtaTm));
sessionHolder.setSynchronizedWithTransaction(true);
// Switch to FlushMode.AUTO, as we have to assume a thread-bound Session
// with FlushMode.NEVER, which needs to allow flushing within the transaction.
FlushMode flushMode = session.getFlushMode();
if (flushMode.lessThan(FlushMode.COMMIT)) {
session.setFlushMode(FlushMode.AUTO);
sessionHolder.setPreviousFlushMode(flushMode);
}
}
}
return session;
}
}
// No transaction active -> simply return default thread-bound Session, if any
// (possibly from OpenSessionInViewFilter/Interceptor).
return sessionHolder.getValidatedSession();
}
catch (Throwable ex) {
throw new DataAccessResourceFailureException("Could not check JTA transaction", ex);
}
}
else {
// No JTA TransactionManager -> simply return default thread-bound Session, if any
// (possibly from OpenSessionInViewFilter/Interceptor).
return sessionHolder.getValidatedSession();
}
}

/**
* Register a JTA synchronization for the given Session, if any.
* @param sessionHolder the existing thread-bound SessionHolder, if any
* @param session the Session to register
* @param sessionFactory the SessionFactory that the Session was created with
* @param jdbcExceptionTranslator SQLExcepionTranslator to use for flushing the
* Session on transaction synchronization (can be <code>null</code>)
*/
private static void registerJtaSynchronization(Session session, SessionFactory sessionFactory,
SQLExceptionTranslator jdbcExceptionTranslator, SessionHolder sessionHolder) {

// JTA synchronization is only possible with a javax.transaction.TransactionManager.
// We'll check the Hibernate SessionFactory: If a TransactionManagerLookup is specified
// in Hibernate configuration, it will contain a TransactionManager reference.
TransactionManager jtaTm = getJtaTransactionManager(sessionFactory, session);
if (jtaTm != null) {
try {
Transaction jtaTx = jtaTm.getTransaction();
if (jtaTx != null) {
int jtaStatus = jtaTx.getStatus();
if (jtaStatus == Status.STATUS_ACTIVE || jtaStatus == Status.STATUS_MARKED_ROLLBACK) {
logger.debug("Registering JTA transaction synchronization for new Hibernate Session");
SessionHolder holderToUse = sessionHolder;
// Register JTA Transaction with existing SessionHolder.
// Create a new SessionHolder if none existed before.
if (holderToUse == null) {
holderToUse = new SessionHolder(jtaTx, session);
}
else {
holderToUse.addSession(jtaTx, session);
}
jtaTx.registerSynchronization(
new SpringJtaSynchronizationAdapter(
new SpringSessionSynchronization(holderToUse, sessionFactory, jdbcExceptionTranslator, true),
jtaTm));
holderToUse.setSynchronizedWithTransaction(true);
if (holderToUse != sessionHolder) {
TransactionSynchronizationManager.bindResource(sessionFactory, holderToUse);
}
}
}
}
catch (Throwable ex) {
throw new DataAccessResourceFailureException(
"Could not register synchronization with JTA TransactionManager", ex);
}
}
}

getNewSession

获取一个新的Session,尽可能共享当前线程绑定的SessionHolder的任何一个Session的数据库连接Connection,这种Connection依赖生命周期的管理在hibernate3.x api中有详细介绍
/**
* Get a new Hibernate Session from the given SessionFactory.
* Will return a new Session even if there already is a pre-bound
* Session for the given SessionFactory.
* <p>Within a transaction, this method will create a new Session
* that shares the transaction's JDBC Connection. More specifically,
* it will use the same JDBC Connection as the pre-bound Hibernate Session.
* @param sessionFactory Hibernate SessionFactory to create the session with
* @param entityInterceptor Hibernate entity interceptor, or {@code null} if none
* @return the new Session
*/
public static Session getNewSession(SessionFactory sessionFactory, Interceptor entityInterceptor) {
Assert.notNull(sessionFactory, "No SessionFactory specified");

try {
SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
if (sessionHolder != null && !sessionHolder.isEmpty()) {
if (entityInterceptor != null) {
return sessionFactory.openSession(sessionHolder.getAnySession().connection(), entityInterceptor);
}
else {
return sessionFactory.openSession(sessionHolder.getAnySession().connection());
}
}
else {
if (entityInterceptor != null) {
return sessionFactory.openSession(entityInterceptor);
}
else {
return sessionFactory.openSession();
}
}
}
catch (HibernateException ex) {
throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex);
}
}


isDeferredCloseActive,initDeferredClose,processDeferredClose,closeSessionOrRegisterDeferredClose
这四个是关注可能的SessionFactory延迟关闭。isDeferredCloseActive判断SessionFactory是否标志位延迟关闭;initDeferredClose标志SessionFactory延迟关闭;processDeferredClose关闭SessionFactory管理的所有延迟的Session;closeSessionOrRegisterDeferredClose将可能的SessionFactory管理的Session延放在延迟Map中,否则直接关闭Session。Session的延迟关闭策略主要在OpenSessionInviewFilter/Interceptor和事务框架中实现。
/**
* Determine whether deferred close is active for the current thread
* and the given SessionFactory.
* @param sessionFactory the Hibernate SessionFactory to check
* @return whether deferred close is active
*/
public static boolean isDeferredCloseActive(SessionFactory sessionFactory) {
Assert.notNull(sessionFactory, "No SessionFactory specified");
Map<SessionFactory, Set<Session>> holderMap = deferredCloseHolder.get();
return (holderMap != null && holderMap.containsKey(sessionFactory));
}

/**
* Initialize deferred close for the current thread and the given SessionFactory.
* Sessions will not be actually closed on close calls then, but rather at a
* {@link #processDeferredClose} call at a finishing point (like request completion).
* <p>Used by {@link org.springframework.orm.hibernate3.support.OpenSessionInViewFilter}
* and {@link org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor}
* when not configured for a single session.
* @param sessionFactory the Hibernate SessionFactory to initialize deferred close for
* @see #processDeferredClose
* @see #releaseSession
* @see org.springframework.orm.hibernate3.support.OpenSessionInViewFilter#setSingleSession
* @see org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor#setSingleSession
*/
public static void initDeferredClose(SessionFactory sessionFactory) {
Assert.notNull(sessionFactory, "No SessionFactory specified");
logger.debug("Initializing deferred close of Hibernate Sessions");
Map<SessionFactory, Set<Session>> holderMap = deferredCloseHolder.get();
if (holderMap == null) {
holderMap = new HashMap<SessionFactory, Set<Session>>();
deferredCloseHolder.set(holderMap);
}
holderMap.put(sessionFactory, new LinkedHashSet<Session>(4));
}

/**
* Process all Hibernate Sessions that have been registered for deferred close
* for the given SessionFactory.
* @param sessionFactory the Hibernate SessionFactory to process deferred close for
* @see #initDeferredClose
* @see #releaseSession
*/
public static void processDeferredClose(SessionFactory sessionFactory) {
Assert.notNull(sessionFactory, "No SessionFactory specified");
Map<SessionFactory, Set<Session>> holderMap = deferredCloseHolder.get();
if (holderMap == null || !holderMap.containsKey(sessionFactory)) {
throw new IllegalStateException("Deferred close not active for SessionFactory [" + sessionFactory + "]");
}
logger.debug("Processing deferred close of Hibernate Sessions");
Set<Session> sessions = holderMap.remove(sessionFactory);
for (Session session : sessions) {
closeSession(session);
}
if (holderMap.isEmpty()) {
deferredCloseHolder.remove();
}
}

/**
* Close the given Session, created via the given factory,
* if it is not managed externally (i.e. not bound to the thread).
* @param session the Hibernate Session to close (may be {@code null})
* @param sessionFactory Hibernate SessionFactory that the Session was created with
* (may be {@code null})
*/
public static void releaseSession(Session session, SessionFactory sessionFactory) {
if (session == null) {
return;
}
// Only close non-transactional Sessions.
if (!isSessionTransactional(session, sessionFactory)) {
closeSessionOrRegisterDeferredClose(session, sessionFactory);
}
}

/**
* 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);
}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值