/// <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) { DbProviderTransactionObject txMgrStateObject = (DbProviderTransactionObject)transaction; IDbConnection con = null; if (dbProvider == null) { throw new ArgumentException("DbProvider is required to be set on AdoPlatformTransactionManager"); } try { if (txMgrStateObject.ConnectionHolder == null || txMgrStateObject.ConnectionHolder.SynchronizedWithTransaction) { IDbConnection newCon = DbProvider.CreateConnection(); if (log.IsDebugEnabled) { log.Debug("Acquired Connection [" + newCon + ", " + newCon.ConnectionString + "] for ADO.NET transaction"); } newCon.Open(); //TODO isolation level mgmt - will need to abstract out SQL used to specify this in DbMetaData //MSDN docs... //With one exception, you can switch from one isolation level to another at any time during a transaction. The exception occurs when changing from any isolation level to SNAPSHOT isolation //IsolationLevel previousIsolationLevel = IDbTransaction newTrans = newCon.BeginTransaction(definition.TransactionIsolationLevel); txMgrStateObject.SetConnectionHolder(new ConnectionHolder(newCon, newTrans), true); } txMgrStateObject.ConnectionHolder.SynchronizedWithTransaction = true; con = txMgrStateObject.ConnectionHolder.Connection; txMgrStateObject.ConnectionHolder.TransactionActive = true; int timeout = DetermineTimeout(definition); if (timeout != DefaultTransactionDefinition.TIMEOUT_DEFAULT) { txMgrStateObject.ConnectionHolder.TimeoutInSeconds = timeout; } //Bind transactional resources to thread if (txMgrStateObject.NewConnectionHolder) { TransactionSynchronizationManager.BindResource(DbProvider, txMgrStateObject.ConnectionHolder); } } //TODO catch specific exception catch (Exception e) { ConnectionUtils.DisposeConnection(con, DbProvider); throw new CannotCreateTransactionException("Could not create ADO.NET connection for transaction", e); } }
/// <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) { DbProviderTransactionObject txMgrStateObject = (DbProviderTransactionObject)transaction; txMgrStateObject.ConnectionHolder = null; ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.UnbindResource(DbProvider); return(conHolder); }
/// <summary> /// Check if the given transaction object indicates an existing, /// i.e. already begun, transaction. /// </summary> /// <param name="transaction"> /// Transaction object returned by /// <see cref="Spring.Transaction.Support.AbstractPlatformTransactionManager.DoGetTransaction"/>. /// </param> /// <returns>True if there is an existing transaction.</returns> /// <exception cref="Spring.Transaction.TransactionException"> /// In the case of system errors. /// </exception> protected override bool IsExistingTransaction(object transaction) { DbProviderTransactionObject txMgrStateObject = (DbProviderTransactionObject)transaction; return(txMgrStateObject.ConnectionHolder != null && txMgrStateObject.ConnectionHolder.TransactionActive); }
/// <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() { DbProviderTransactionObject txMgrStateObject = new DbProviderTransactionObject(); txMgrStateObject.SavepointAllowed = NestedTransactionsAllowed; ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.GetResource(DbProvider); txMgrStateObject.SetConnectionHolder(conHolder, false); return txMgrStateObject; }
/// <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() { DbProviderTransactionObject txMgrStateObject = new DbProviderTransactionObject(); txMgrStateObject.SavepointAllowed = NestedTransactionsAllowed; ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.GetResource(DbProvider); txMgrStateObject.SetConnectionHolder(conHolder, false); return(txMgrStateObject); }
/// <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) { DbProviderTransactionObject txMgrStateObject = (DbProviderTransactionObject)status.Transaction; if (status.Debug) { IDbConnection conn = txMgrStateObject.ConnectionHolder.Connection; log.Debug("Setting ADO.NET transaction [" + conn + ", " + conn.ConnectionString + "] rollback-only."); } txMgrStateObject.SetRollbackOnly(); }
/// <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) { DbProviderTransactionObject txMgrStateObject = (DbProviderTransactionObject)status.Transaction; IDbConnection conn = txMgrStateObject.ConnectionHolder.Connection; IDbTransaction trans = txMgrStateObject.ConnectionHolder.Transaction; if (status.Debug) { log.Debug("Rolling back ADO.NET transaction on Connection [" + conn + ", " + conn.ConnectionString + "]"); } try { trans.Rollback(); } catch (Exception e) { throw new TransactionSystemException("Could not rollback ADO.NET transaction", e); } }
protected override void DoCleanupAfterCompletion(object transaction) { DbProviderTransactionObject txMgrStateObject = (DbProviderTransactionObject)transaction; if (txMgrStateObject.NewConnectionHolder) { TransactionSynchronizationManager.UnbindResource(DbProvider); } IDbConnection con = txMgrStateObject.ConnectionHolder.Connection; if (log.IsDebugEnabled) { log.Debug("Releasing ADO.NET Connection [" + con + ", " + con.ConnectionString + "] after transaction"); } ConnectionUtils.DisposeConnection(con, DbProvider); //TODO clear out IDbTransaction object? txMgrStateObject.ConnectionHolder.Clear(); }