Transaction promoted to Distributed Transaction(MSDTC)

作者: 皮业勇  来源: 博客园  发布时间:2011-08-24 17:42  阅读:63 次   原文链接   [收藏]  

在程序中抛出如下异常:

Message: AutoPopulatePlatformCommand error:Network access for Distributed Transaction Manager (MSDTC) has been disabled. Please enable DTC for network access in the security configuration for MSDTC using the Component Services Administrative tool..Detial:   at System.Transactions.Oletx.OletxTransactionManager.ProxyException(COMException comException)

   at System.Transactions.TransactionInterop.GetOletxTransactionFromTransmitterPropigationToken(Byte[] propagationToken)

   at System.Transactions.TransactionStatePSPEOperation.PSPEPromote(InternalTransaction tx)

   at System.Transactions.TransactionStateDelegatedBase.EnterState(InternalTransaction tx)

   at System.Transactions.EnlistableStates.Promote(InternalTransaction tx)

   at System.Transactions.Transaction.Promote()

   at System.Transactions.TransactionInterop.ConvertToOletxTransaction(Transaction transaction)

   at System.Transactions.TransactionInterop.GetExportCookie(Transaction transaction, Byte[] whereabouts)

   at System.Data.SqlClient.SqlInternalConnection.GetTransactionCookie(Transaction transaction, Byte[] whereAbouts)

   at System.Data.SqlClient.SqlInternalConnection.EnlistNonNull(Transaction tx)

   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()

。。。。。。

 

运行环境:

.net framework 4.0,

SQL Server 2008 R2,

Windows Server 2008 R2

起初怀疑是使用了nested TransactionScope,导致自动提升为distributed transaction,而系统将MSDTC服务关闭,所以导致异常。将MSDTC服务打开,能正常运行。

 

程序只需要访问一个数据库,却打开了MSDTC,很明显adds unnecessary overhead and decreases performance.那么为什么会提升为Distributed呢?

 

Google到如下信息:

 

这里只用到了一种resource type,也没有多个databasepromoted只有一种情况:nested connections

写如下测试程序:

      using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, tOptions))

      {

        var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["FLMConnectionString1"].ConnectionString);

        connection.Open();

        var connection2 = new SqlConnection(ConfigurationManager.ConnectionStrings["FLMConnectionString1"].ConnectionString);

        connection2.Open();

 

        scope.Complete();

      }

抛出如下异常:

 

      using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, tOptions))

      {

        var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["FLMConnectionString1"].ConnectionString);

        connection.Open();

        connection.Close();

        var connection2 = new SqlConnection(ConfigurationManager.ConnectionStrings["FLMConnectionString1"].ConnectionString);

        connection2.Open();

 

        scope.Complete();

      }

没有异常

原因确定:多个连接同时打开, 即使是相同的Connection string,也会promoted to distributed tranaction.

 

在做测试时,犯了一个低级错误,起初写的数据库访问代码如下:

    public void Add(string connectionString, string commandText)

    {

      using (var connection = new SqlConnection(connectionString))

      {

        using (var command = new SqlCommand(commandText, connection))

        {

          command.CommandType = CommandType.Text;

 

          connection.Open();

 

          try

          {

            command.ExecuteNonQuery();

          }

          finally

          {

            connection.Close();

          }

        }

      }

    }

为了测试多个数据库连接是否会导致promoted,将connection.Close()语句注释掉,发现多次调用Add,使用nested transactionscope,多表操作,多表查询,添加,均不会导致promoted。为什么呢?其实是因为使用了using关键字,离开usingscope时,SqlConnectionDispose方法被调用,自动释放了连接,至始至终都是有一个数据库连接,所以不会promoted。通过测试,还确定nested TransactionScope的的确确能够工作,而且使用非常简便,能根据需要自动promoted to distributed transaction

 

有文章说SQL Servier 2005多次连接就会自动提升,没有环境,没做测试,而且已经都SQL Server 2008 R2了,以后也不会用2005了吧,如果这要用,可以写一个Connection Manager类来管理数据库连接,保证通过一个transaction里的所有db访问都使用这一个连接,只有transaction结束了才释放。