/// <summary> /// Perform an actual commit on the given transaction. /// </summary> /// <param name="status">The status representation of the transaction.</param> /// <remarks> /// <p> /// An implementation does not need to check the rollback-only flag. /// </p> /// </remarks> /// <exception cref="Spring.Transaction.TransactionException"> /// In the case of system errors. /// </exception> protected override void DoCommit(DefaultTransactionStatus status) { HibernateTransactionObject txObject = (HibernateTransactionObject)status.Transaction; if (status.Debug) { log.Debug("Committing Hibernate transaction on Session [" + txObject.SessionHolder.Session + "]"); } try { txObject.SessionHolder.Transaction.Commit(); } // Note, unfortunate collision of namespaces/classname for NHibernate.TransactionException // and Spring.Data.NHibernate requires this wierd construct. catch (Exception ex) { Type nhibTxExceptiontype = TypeResolutionUtils.ResolveType("NHibernate.TransactionException, NHibernate"); if (ex.GetType().Equals(nhibTxExceptiontype)) { // assumably from commit call to the underlying ADO.NET connection throw new TransactionSystemException("Could not commit Hibernate transaction", ex); } HibernateException hibEx = ex as HibernateException; if (hibEx != null) { // assumably failed to flush changes to database throw ConvertHibernateAccessException(hibEx); } throw; } }
/// <summary> /// Return the current transaction object. /// </summary> /// <returns>The current transaction object.</returns> /// <exception cref="Spring.Transaction.CannotCreateTransactionException"> /// If transaction support is not available. /// </exception> /// <exception cref="Spring.Transaction.TransactionException"> /// In the case of lookup or system errors. /// </exception> protected override object DoGetTransaction() { HibernateTransactionObject txObject = new HibernateTransactionObject(); txObject.SavepointAllowed = NestedTransactionsAllowed; if (TransactionSynchronizationManager.HasResource(SessionFactory)) { SessionHolder sessionHolder = (SessionHolder)TransactionSynchronizationManager.GetResource(SessionFactory); if (log.IsDebugEnabled) { log.Debug("Found thread-bound Session [" + sessionHolder.Session + "] for Hibernate transaction"); } txObject.SetSessionHolder(sessionHolder, false); if (DbProvider != null) { ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.GetResource(DbProvider); txObject.ConnectionHolder = conHolder; } } txObject.PromotableTxScopeTransactionObject = new TxScopeTransactionManager.PromotableTxScopeTransactionObject(); return(txObject); }
/// <summary> /// Perform an actual rollback on the given transaction. /// </summary> /// <param name="status">The status representation of the transaction.</param> /// <remarks> /// An implementation does not need to check the new transaction flag. /// </remarks> /// <exception cref="Spring.Transaction.TransactionException"> /// In the case of system errors. /// </exception> protected override void DoRollback(DefaultTransactionStatus status) { HibernateTransactionObject txObject = (HibernateTransactionObject)status.Transaction; if (status.Debug) { log.Debug("Rolling back Hibernate transaction on Session [" + txObject.SessionHolder.Session + "]"); } try { txObject.SessionHolder.Transaction.Rollback(); } catch (HibernateTransactionException ex) { throw new TransactionSystemException("Could not roll back Hibernate transaction", ex); } catch (HibernateException ex) { // Shouldn't really happen, as a rollback doesn't cause a flush. throw ConvertHibernateAccessException(ex); } finally { if (!txObject.NewSessionHolder) { // Clear all pending inserts/updates/deletes in the Session. // Necessary for pre-bound Sessions, to avoid inconsistent state. txObject.SessionHolder.Session.Clear(); } } }
/// <summary> /// Set the given transaction rollback-only. Only called on rollback /// if the current transaction takes part in an existing one. /// </summary> /// <param name="status">The status representation of the transaction.</param> /// <exception cref="Spring.Transaction.TransactionException"> /// In the case of system errors. /// </exception> protected override void DoSetRollbackOnly(DefaultTransactionStatus status) { HibernateTransactionObject txObject = (HibernateTransactionObject)status.Transaction; if (status.Debug) { log.Debug("Setting Hibernate transaction on Session [" + txObject.SessionHolder.Session + "] rollback-only"); } txObject.SetRollbackOnly(); }
/// <summary> /// Cleanup resources after transaction completion. /// </summary> /// <param name="transaction">Transaction object returned by /// <see cref="M:Spring.Transaction.Support.AbstractPlatformTransactionManager.DoGetTransaction"/>.</param> /// <remarks> /// <note> /// This implemenation unbinds the SessionFactory and /// DbProvider from thread local storage and closes the /// ISession. /// </note> /// <p> /// Called after <see cref="M:Spring.Transaction.Support.AbstractPlatformTransactionManager.DoCommit(Spring.Transaction.Support.DefaultTransactionStatus)"/> /// and /// <see cref="M:Spring.Transaction.Support.AbstractPlatformTransactionManager.DoRollback(Spring.Transaction.Support.DefaultTransactionStatus)"/> /// execution on any outcome. /// </p> /// <p> /// Should not throw any exceptions but just issue warnings on errors. /// </p> /// </remarks> protected override void DoCleanupAfterCompletion(object transaction) { HibernateTransactionObject txObject = (HibernateTransactionObject)transaction; // Remove the session holder from the thread. if (txObject.NewSessionHolder) { TransactionSynchronizationManager.UnbindResource(SessionFactory); } // Remove the ADO.NET connection holder from the thread, if exposed. if (DbProvider != null) { TransactionSynchronizationManager.UnbindResource(DbProvider); } /* * try * { * //TODO investigate isolation level settings... * //IDbConnection con = txObject.SessionHolder.Session.Connection; * //AdoUtils.ResetConnectionAfterTransaction(con, txObject.PreviousIsolationLevel); * } * catch (HibernateException ex) * { * log.Info("Could not access ADO.NET IDbConnection of Hibernate Session", ex); * } */ ISession session = txObject.SessionHolder.Session; if (txObject.NewSessionHolder) { if (log.IsDebugEnabled) { log.Debug("Closing Hibernate Session [" + session + "] after transaction"); } SessionFactoryUtils.CloseSessionOrRegisterDeferredClose(session, SessionFactory); } else { if (log.IsDebugEnabled) { log.Debug("Not closing pre-bound Hibernate Session [" + session + "] after transaction"); } if (txObject.SessionHolder.AssignedPreviousFlushMode) { session.FlushMode = txObject.SessionHolder.PreviousFlushMode; } } txObject.SessionHolder.Clear(); }
/// <summary> /// Suspend the resources of the current transaction. /// </summary> /// <param name="transaction"> /// Transaction object returned by /// <see cref="Spring.Transaction.Support.AbstractPlatformTransactionManager.DoGetTransaction"/>. /// </param> /// <returns> /// An object that holds suspended resources (will be kept unexamined for passing it into /// <see cref="Spring.Transaction.Support.AbstractPlatformTransactionManager.DoResume"/>.) /// </returns> /// <remarks> /// Transaction synchronization will already have been suspended. /// </remarks> /// <exception cref="Spring.Transaction.IllegalTransactionStateException"> /// If suspending is not supported by the transaction manager implementation. /// </exception> /// <exception cref="Spring.Transaction.TransactionException"> /// in case of system errors. /// </exception> protected override object DoSuspend(object transaction) { HibernateTransactionObject txObject = (HibernateTransactionObject)transaction; txObject.SetSessionHolder(null, false); SessionHolder sessionHolder = (SessionHolder)TransactionSynchronizationManager.UnbindResource(SessionFactory); ConnectionHolder connectionHolder = null; if (DbProvider != null) { connectionHolder = (ConnectionHolder)TransactionSynchronizationManager.UnbindResource(DbProvider); } return(new SuspendedResourcesHolder(sessionHolder, connectionHolder)); }
/// <summary> /// Cleanup resources after transaction completion. /// </summary> /// <param name="transaction">Transaction object returned by /// <see cref="M:Spring.Transaction.Support.AbstractPlatformTransactionManager.DoGetTransaction"/>.</param> /// <remarks> /// <note> /// This implemenation unbinds the SessionFactory and /// DbProvider from thread local storage and closes the /// ISession. /// </note> /// <p> /// Called after <see cref="M:Spring.Transaction.Support.AbstractPlatformTransactionManager.DoCommit(Spring.Transaction.Support.DefaultTransactionStatus)"/> /// and /// <see cref="M:Spring.Transaction.Support.AbstractPlatformTransactionManager.DoRollback(Spring.Transaction.Support.DefaultTransactionStatus)"/> /// execution on any outcome. /// </p> /// <p> /// Should not throw any exceptions but just issue warnings on errors. /// </p> /// </remarks> protected override void DoCleanupAfterCompletion(object transaction) { HibernateTransactionObject txObject = (HibernateTransactionObject)transaction; // Remove the session holder from the thread. if (txObject.NewSessionHolder) { TransactionSynchronizationManager.UnbindResource(SessionFactory); } // Remove the ADO.NET connection holder from the thread, if exposed. if (DbProvider != null) { TransactionSynchronizationManager.UnbindResource(DbProvider); } ISession session = txObject.SessionHolder.Session; if (txObject.NewSessionHolder) { if (log.IsDebugEnabled) { log.Debug("Closing Hibernate Session [" + session + "] after transaction"); } SessionFactoryUtils.CloseSessionOrRegisterDeferredClose(session, SessionFactory); } else { if (log.IsDebugEnabled) { log.Debug("Not closing pre-bound Hibernate Session [" + session + "] after transaction"); } if (txObject.SessionHolder.AssignedPreviousFlushMode) { session.FlushMode = txObject.SessionHolder.PreviousFlushMode; } } txObject.SessionHolder.Clear(); }
/// <summary> /// Perform an actual rollback on the given transaction. /// </summary> /// <param name="status">The status representation of the transaction.</param> /// <remarks> /// An implementation does not need to check the new transaction flag. /// </remarks> /// <exception cref="Spring.Transaction.TransactionException"> /// In the case of system errors. /// </exception> protected override void DoRollback(DefaultTransactionStatus status) { HibernateTransactionObject txObject = (HibernateTransactionObject)status.Transaction; if (!txObject.NewSessionHolder) { // Clear all pending inserts/updates/deletes in the Session. // Necessary for pre-bound Sessions, to avoid inconsistent state. txObject.SessionHolder.Session.Clear(); } DoTxScopeRollback(status); return; /* HibernateTransactionObject txObject = (HibernateTransactionObject)status.Transaction; * * if (status.Debug) * { * log.Debug("Rolling back Hibernate transaction on Session [" + * txObject.SessionHolder.Session + "]"); * } * try * { * if (txObject.SessionHolder.Session != null && txObject.SessionHolder.Transaction != null && !txObject.SessionHolder.Transaction.IsActive) * { * return; * } * * IDbTransaction adoTx = GetIDbTransaction(txObject.SessionHolder.Transaction); * * if (adoTx != null && adoTx.Connection != null) * { * txObject.SessionHolder.Transaction.Rollback(); * } * else * { * if (status.Debug) * { * log.Debug("Unable to RollBack Hibernate transaction; connection for Hibernate transaction on Session [" + * txObject.SessionHolder.Session + "] was null"); * } * } * * } * catch (HibernateTransactionException ex) * { * throw new TransactionSystemException("Could not roll back Hibernate transaction", ex); * } * catch (HibernateException ex) * { * // Shouldn't really happen, as a rollback doesn't cause a flush. * throw ConvertHibernateAccessException(ex); * } * finally * { * if (!txObject.NewSessionHolder) * { * // Clear all pending inserts/updates/deletes in the Session. * // Necessary for pre-bound Sessions, to avoid inconsistent state. * txObject.SessionHolder.Session.Clear(); * } * DoTxScopeRollback(status); * }*/ }
/// <summary> /// Begin a new transaction with the given transaction definition. /// </summary> /// <param name="transaction"> /// Transaction object returned by /// <see cref="Spring.Transaction.Support.AbstractPlatformTransactionManager.DoGetTransaction"/>. /// </param> /// <param name="definition"> /// <see cref="Spring.Transaction.ITransactionDefinition"/> instance, describing /// propagation behavior, isolation level, timeout etc. /// </param> /// <remarks> /// Does not have to care about applying the propagation behavior, /// as this has already been handled by this abstract manager. /// </remarks> /// <exception cref="Spring.Transaction.TransactionException"> /// In the case of creation or system errors. /// </exception> protected override void DoBegin(object transaction, ITransactionDefinition definition) { TxScopeTransactionManager.PromotableTxScopeTransactionObject promotableTxScopeTransactionObject = ((HibernateTransactionObject)transaction).PromotableTxScopeTransactionObject; try { DoTxScopeBegin(promotableTxScopeTransactionObject, definition); } catch (Exception e) { throw new CannotCreateTransactionException("Transaction Scope failure on begin", e); } HibernateTransactionObject txObject = (HibernateTransactionObject)transaction; if (DbProvider != null && TransactionSynchronizationManager.HasResource(DbProvider) && !txObject.ConnectionHolder.SynchronizedWithTransaction) { throw new IllegalTransactionStateException( "Pre-bound ADO.NET Connection found - HibernateTransactionManager does not support " + "running within AdoTransactionManager if told to manage the DbProvider itself. " + "It is recommended to use a single HibernateTransactionManager for all transactions " + "on a single DbProvider, no matter whether Hibernate or ADO.NET access."); } ISession session = null; try { if (txObject.SessionHolder == null || txObject.SessionHolder.SynchronizedWithTransaction) { IInterceptor interceptor = EntityInterceptor; ISession newSession = (interceptor != null ? SessionFactory.OpenSession(interceptor) : SessionFactory.OpenSession()); if (log.IsDebugEnabled) { log.Debug("Opened new Session [" + newSession + "] for Hibernate transaction"); } txObject.SetSessionHolder(new SessionHolder(newSession), true); } txObject.SessionHolder.SynchronizedWithTransaction = true; session = txObject.SessionHolder.Session; IDbConnection con = session.Connection; //TODO isolation level mgmt //IsolationLevel previousIsolationLevel = if (definition.ReadOnly && txObject.NewSessionHolder) { // Just set to NEVER in case of a new Session for this transaction. session.FlushMode = FlushMode.Never; } if (!definition.ReadOnly && !txObject.NewSessionHolder) { // We need AUTO or COMMIT for a non-read-only transaction. FlushMode flushMode = session.FlushMode; if (FlushMode.Never == flushMode) { session.FlushMode = FlushMode.Auto; txObject.SessionHolder.PreviousFlushMode = flushMode; } } // Add the Hibernate transaction to the session holder. // for now pass in tx options isolation level. ITransaction hibernateTx = session.BeginTransaction(definition.TransactionIsolationLevel); IDbTransaction adoTx = GetIDbTransaction(hibernateTx); // Add the Hibernate transaction to the session holder. txObject.SessionHolder.Transaction = hibernateTx; // Register transaction timeout. int timeout = DetermineTimeout(definition); if (timeout != DefaultTransactionDefinition.TIMEOUT_DEFAULT) { txObject.SessionHolder.TimeoutInSeconds = timeout; } // Register the Hibernate Session's ADO.NET Connection/TX pair for the DbProvider, if set. if (DbProvider != null) { //investigate passing null for tx. ConnectionHolder conHolder = new ConnectionHolder(con, adoTx); if (timeout != DefaultTransactionDefinition.TIMEOUT_DEFAULT) { conHolder.TimeoutInMillis = definition.TransactionTimeout; } if (log.IsDebugEnabled) { log.Debug("Exposing Hibernate transaction as ADO transaction [" + con + "]"); } TransactionSynchronizationManager.BindResource(DbProvider, conHolder); txObject.ConnectionHolder = conHolder; } // Bind the session holder to the thread. if (txObject.NewSessionHolder) { TransactionSynchronizationManager.BindResource(SessionFactory, txObject.SessionHolder); } } catch (Exception ex) { SessionFactoryUtils.CloseSession(session); throw new CannotCreateTransactionException("Could not open Hibernate Session for transaction", ex); } }
/// <summary> /// Return the current transaction object. /// </summary> /// <returns>The current transaction object.</returns> /// <exception cref="Spring.Transaction.CannotCreateTransactionException"> /// If transaction support is not available. /// </exception> /// <exception cref="Spring.Transaction.TransactionException"> /// In the case of lookup or system errors. /// </exception> protected override object DoGetTransaction() { HibernateTransactionObject txObject = new HibernateTransactionObject(); txObject.SavepointAllowed = NestedTransactionsAllowed; if (TransactionSynchronizationManager.HasResource(SessionFactory)) { SessionHolder sessionHolder = (SessionHolder)TransactionSynchronizationManager.GetResource(SessionFactory); if (log.IsDebugEnabled) { log.Debug("Found thread-bound Session [" + sessionHolder.Session + "] for Hibernate transaction"); } txObject.SetSessionHolder(sessionHolder, false); if (DbProvider != null) { ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.GetResource(DbProvider); txObject.ConnectionHolder = conHolder; } } return txObject; }