Transaction promoted to Distributed Transaction(MSDTC)
在程序中抛出如下异常:
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,也没有多个database,promoted只有一种情况: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关键字,离开using的scope时,SqlConnection的Dispose方法被调用,自动释放了连接,至始至终都是有一个数据库连接,所以不会promoted。通过测试,还确定nested TransactionScope的的确确能够工作,而且使用非常简便,能根据需要自动promoted to distributed transaction。
有文章说SQL Servier 2005多次连接就会自动提升,没有环境,没做测试,而且已经都SQL Server 2008 R2了,以后也不会用2005了吧,如果这要用,可以写一个Connection Manager类来管理数据库连接,保证通过一个transaction里的所有db访问都使用这一个连接,只有transaction结束了才释放。