据我所知,MSDTC只在以下情况下参与:
您正在查询链接到的事务中的视图/表 另一台服务器
您正在使用两个SqlConnections(或者它是什么 NHibernate在单个TransactionScope中使用)
您在TransactionScope中搜索另一个事务组件(如MSMQ或事务文件系统)。
未提及的其他情况。
如果我禁用MSDTC并运行以下代码,我会收到(服务器上的MSDTC'服务器'不可用)错误。
public bool Add(PurchaseOrderInfo purchaseOrderInfo)
{
using (TransactionScope ts = new TransactionScope())
{
using (SqlConnection Cnn = new SqlConnection(SqlHelper.ConnStr))
{
Cnn.Open();
try
{
using (SqlDataReader rdr = SqlHelper.ExecuteReader(/*Tr*/Cnn, "spPurchaseOrderAdd", purchaseOrderInfo.ExpectedShipment.ShipmentID, purchaseOrderInfo.CreateDate, purchaseOrderInfo.CustomerNotes, purchaseOrderInfo.Status, purchaseOrderInfo.PurchaseOrderNumber))
{
if (rdr.Read())
FillPurchaseOrderInfo(rdr, ref purchaseOrderInfo, GettingDepthEnum.Level_0);
else
{
return false;
}
}
foreach (PurchaseOrderDetailInfo detailInfo in purchaseOrderInfo.Details)
{
throw new Exception("Test");
//if (!AddPurchaseOrderDetail(Tr, purchaseOrderInfo, detailInfo))
{
//Tr.Rollback();
return false;
}
}
return true;
}
catch (Exception ex)
{
throw ex;
}
ts.Complete();
}
}
}
我错过了什么吗?
更新: 存储过程包含一个简单的insert语句:
INSERT INTO tblPurchaseOrder
(ShipmentID, CreateDate, CustomerNotes, PurchaseOrderState, PurchaseOrderNumber, LastActivityDate)
VALUES
(@ShipmentID, @CreateDate, @CustomerNotes, @PurchaseOrderState, @PurchaseOrderNumber, GETDATE());
--Step 2: return row that INSERTED to Client Computer.
SELECT dbo.viwGetPurchaseOrderWeight.Weight,* FROM tblPurchaseOrder LEFT OUTER JOIN viwGetPurchaseOrderWeight ON viwGetPurchaseOrderWeight.PurchaseOrderID = tblPurchaseOrder.PurchaseOrderID WHERE (tblPurchaseOrder.PurchaseOrderID = Scope_Identity());
UPDATE2: 当关闭MSDTC时,执行到达此行时抛出异常:
using (SqlDataReader rdr = SqlHelper.ExecuteReader(/*Tr*/Cnn, "spPurchaseOrderAdd", purchaseOrderInfo.ExpectedShipment.ShipmentID, purchaseOrderInfo.CreateDate, purchaseOrderInfo.CustomerNotes, purchaseOrderInfo.Status, purchaseOrderInfo.PurchaseOrderNumber))
表示后续行无效。
答案 0 :(得分:2)
请确保不要再打开连接,
using (TransactionScope transactionScope = new TransactionScope()) {
using (SqlConnection connection = new SqlConnection(connectionString)) {
connection.Open();
connection.Close();
connection.Open(); // escalates to DTC
}
}
答案 1 :(得分:1)
根据您的帖子与堆栈跟踪,EntLib类正在打开另一个连接。我们需要将其从交易中排除。在限制交易范围内将您的电话转接至ExecuteReader
:
SqlDataReader rdr;
using (var tsSuppress = new TransactionScope(TransactionScopeOption.Suppress))
rdr = SqlHelper.ExecuteReader(...)
这会暂时将Transaction.Current
设置为null,以便新连接不会接收事务。
作为旁注,堆栈跟踪使我们能够找到问题的根本原因。
答案 2 :(得分:0)
检查堆栈跟踪后,似乎SQLHelper类正在打开一个连接,以从数据库中获取存储过程所需的参数列表:
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj)
at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
at System.Data.SqlClient.SqlDataReader.ConsumeMetaData()
at System.Data.SqlClient.SqlDataReader.get_MetaData()
at System.Data.SqlClient.TdsParser.TdsExecuteTransactionManagerRequest(Byte[] buffer, TransactionManagerRequestType request, String transactionName, TransactionManagerIsolationLevel isoLevel, Int32 timeout, SqlInternalTransaction transaction, TdsParserStateObject stateObj, Boolean isDelegateControlRequest)
at System.Data.SqlClient.TdsParser.GetDTCAddress(Int32 timeout, TdsParserStateObject stateObj)
at System.Data.SqlClient.SqlInternalConnectionTds.GetDTCAddress()
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()
at Microsoft.ApplicationBlocks.Data.SqlHelperParameterCache.DiscoverSpParameterSet(SqlConnection connection, String spName, Boolean includeReturnValueParameter)
at Microsoft.ApplicationBlocks.Data.SqlHelperParameterCache.GetSpParameterSetInternal(SqlConnection connection, String spName, Boolean includeReturnValueParameter)
at Microsoft.ApplicationBlocks.Data.SqlHelperParameterCache.GetSpParameterSet(SqlConnection connection, String spName, Boolean includeReturnValueParameter)
at Microsoft.ApplicationBlocks.Data.SqlHelperParameterCache.GetSpParameterSet(SqlConnection connection, String spName)
at Microsoft.ApplicationBlocks.Data.SqlHelper.ExecuteReader(SqlConnection connection, String spName, Object[] parameterValues)
at AlefTextileProduction.SQLServerDAL.PurchaseOrder.Add(PurchaseOrderInfo purchaseOrderInfo)
我正试图找到解决方案!!
答案 3 :(得分:0)
在查看SQLHelper
的代码时,如果您使用ExecuteReader
的重载来获取SqlParameter
个实例而不仅仅是参数值,那么您将保存该步骤其中SQLHelper
试图找出哪个参数映射到什么值 - 从而节省了第二次访问数据库和第二次连接以及将您的交易提升到MSDTC。
根据code I'm looking at,这是你应该调用的方法:
Public Overloads Shared Function ExecuteReader(ByVal connectionString As String, _
ByVal commandType As CommandType, _
ByVal commandText As String, _
ByVal ParamArray commandParameters() As SqlParameter) As SqlDataReader
如果这不起作用,那么我建议你推出自己的DAL。 :)
希望这有帮助。