如何在TransactionScope中包装IDbTransactions

时间:2011-06-08 10:26:14

标签: c# transactions transactionscope

我有几个代码方法,如下所示:

using (var connection = this.connectionFactory.GetConnection())
{
    connection.Open();
    using (var transaction = connection.BeginTransaction())
    {
        using (var command = connection.CreateCommand())
        {
            command.Transaction = transaction;
            command.CommandText = "foo";
            command.ExecuteNonQuery();
            transaction.Commit();
        }
    }
}

我现在需要在外部事务中一起调用其中几个方法,所以我这样做了:

using (var transactionScope = new TransactionScope(TransactionScopeOption.RequiresNew))
{
    method1();
    method2();
    method3();
}

但它正在做:

The operation is not valid for the state of the transaction.
   at System.Transactions.TransactionState.EnlistPromotableSinglePhase(InternalTransaction tx, IPromotableSinglePhaseNotification promotableSinglePhaseNotification, Transaction atomicTransaction)
   at System.Transactions.Transaction.EnlistPromotableSinglePhase(IPromotableSinglePhaseNotification promotableSinglePhaseNotification)
   at System.Data.SqlClient.SqlInternalConnection.EnlistNonNull(Transaction tx)
   at System.Data.SqlClient.SqlInternalConnection.Enlist(Transaction tx)
   at System.Data.SqlClient.SqlInternalConnectionTds.Activate(Transaction transaction)
   at System.Data.ProviderBase.DbConnectionInternal.ActivateConnection(Transaction transaction)
   at System.Data.ProviderBase.DbConnectionPool.GetConnection(DbConnection owningObject)
   at System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection)
   at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory)
   at System.Data.SqlClient.SqlConnection.Open()

我是否需要将IDbTransactions替换为TransactionScopes

我应该将TransactionScopeOption用于外部范围?我猜我想要RequiresNew为外部,Required为内部?

这些方法仍然会被单独调用(即没有外部TransactionScope以及一起调用,所以我仍然需要它们在事务上是安全的。

由于

3 个答案:

答案 0 :(得分:6)

我相信您在这里混合使用技术,应避免同时使用TransactionScopeDbTransaction,因为TransactionScope会创建隐式事务。

所以我建议让你的方法类似于:

using (var connection = this.connectionFactory.GetConnection())
{
    connection.Open();
    using (TransactionScope scope = new TransactionScope())
    {
        using (var command = connection.CreateCommand())
        {
            command.CommandText = "foo";
            command.ExecuteNonQuery();
        }
        scope.Complete();
    }
}

然后你可以一起打电话给他们:

using (var scope = new TransactionScope(TransactionScopeOption.RequiresNew))
{
    method1();
    method2();
    method3();

    scope.Complete();
}

您调用的方法将共享同一个事务。

答案 1 :(得分:0)

我猜你做得对。 内部事务注册在外部事务的相同范围内,整个事务将回滚。 要有一个新的transactioncope,你已经指定了“requiresnew”。(你已经提到了) 为了更清晰,请参阅这篇文章。 http://web.archive.org/web/20091012162649/http://www.pluralsight.com/community/blogs/jimjohn/archive/2005/06/18/11451.aspx

答案 2 :(得分:0)

我不确定我会说什么,但在阅读之后:http://msdn.microsoft.com/en-us/library/ms172152(v=vs.80).aspx#sectionSection3

我认为您应该在子方法中使用TransactionScope,但我们选择Required。因此,当它们被单独调用时,您仍然有一个事务,当您使用upper方法调用它们时,事务将被集成到环境事务中。