这篇文章的基本问题是“为什么非升级的LTM交易会受到质疑?”
我收到System.Transactions.TransactionInDoubtException,我无法解释原因。不幸的是我无法重现这个问题,但根据跟踪文件它确实发生了。我正在使用SQL 2005,连接到一个数据库并使用一个SQLConnection,所以我不希望进行促销。错误消息表示超时。但是,有时我会收到一条超时消息,但异常是事务已中止而不是有疑问,这更容易处理。
这是完整的堆栈跟踪:
System.Transactions.TransactionInDoubtException: The transaction is in doubt. ---> System.Data.SqlClient.SqlException: Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding. at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj) at System.Data.SqlClient.TdsParserStateObject.ReadSniError(TdsParserStateObject stateObj, UInt32 error) at System.Data.SqlClient.TdsParserStateObject.ReadSni(DbAsyncResult asyncResult, TdsParserStateObject stateObj) at System.Data.SqlClient.TdsParserStateObject.ReadNetworkPacket() at System.Data.SqlClient.TdsParserStateObject.ReadBuffer() at System.Data.SqlClient.TdsParserStateObject.ReadByte() at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj) 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.SqlInternalConnectionTds.ExecuteTransactionYukon(TransactionRequest transactionRequest, String transactionName, IsolationLevel iso, SqlInternalTransaction internalTransaction, Boolean isDelegateControlRequest) at System.Data.SqlClient.SqlInternalConnectionTds.ExecuteTransaction(TransactionRequest transactionRequest, String name, IsolationLevel iso, SqlInternalTransaction internalTransaction, Boolean isDelegateControlRequest) at System.Data.SqlClient.SqlDelegatedTransaction.SinglePhaseCommit(SinglePhaseEnlistment enlistment) --- End of inner exception stack trace --- at System.Transactions.TransactionStateInDoubt.EndCommit(InternalTransaction tx) at System.Transactions.CommittableTransaction.Commit() at System.Transactions.TransactionScope.InternalDispose() at System.Transactions.TransactionScope.Dispose()
有什么想法吗?为什么我会怀疑,当我得到它时我该怎么办?
编辑以获取更多信息
我实际上仍然没有这方面的答案。我所意识到的是,交易实际上是部分提交的。一个表获取插入但另一个表未获得更新。代码是HEAVILY跟踪,没有太多空间让我错过一些东西。
有没有办法可以轻松找出交易是否已被提升。我们可以从堆栈跟踪中判断它是否存在?单一阶段提交(在strack trace中)似乎表明没有向我推广,但也许我错过了一些东西。如果它没有得到提升那么它怎么会有疑问。
这个难题的另一个有趣的部分是我创建了当前事务的克隆。我这样做是为了解决这个问题。 http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=914869&SiteID=1
不幸的是,我不知道这个问题是否已经解决。也许创建克隆会导致问题。这是相关代码
using (TransactionScope ts = new TransactionScope())
{
transactionCreated = true;
//part of the workarround for microsoft defect mentioned in the beginning of this class
Transaction txClone = Transaction.Current.Clone();
transactions[txClone] = txClone;
Transaction.Current.TransactionCompleted += new TransactionCompletedEventHandler(TransactionCompleted);
MyTrace.WriteLine("Transaction clone stored and attached to event");
m_dataProvider.PersistPackage(ControllerID, package);
MyTrace.WriteLine("Package persisted");
m_dataProvider.PersistTransmissionControllerStatus(this);
MyTrace.WriteLine("Transmission controlled updated");
ts.Complete();
}
由于
答案 0 :(得分:12)
目前接受的答案是,非升级的LTM(非MSDTC)交易永远不会有疑问。经过对类似问题的大量研究后,我发现这是不正确的。
由于实现单阶段提交协议的方式,在事务管理器将SinglePhaseCommit请求发送给其下属之后,事务处于“怀疑”状态的时间很短。下属回复承诺/中止/或准备(需要升级/升级到MSDTC)消息。如果在此期间连接丢失,则事务处于“怀疑状态”,b / c,当事务管理器要求下属执行SinglePhaseCommit时,它从未收到响应。
从MSDN Single-Phase Commit开始,还可以看到"单阶段提交流程"图片在这个答案的底部:
这种优化有一个可能的缺点:如果 事务管理器与下级参与者失去联系 在发送单阶段提交请求之后但在收到之前 结果通知,它没有可靠的恢复机制 交易的实际结果。因此,交易 经理向任何申请或选民发送In Inouboub结果 等待信息结果通知
此处还有一些我发现的事件的实例,它们导致System.Transaction升级/升级到MSDTC事务(这与OP没有直接关系,但我发现它非常有用。在VS 2013中测试过,SQL Server 2008 R2,.NET 4.5,除非另有说明):
以下是导致升级的MS官方列表:http://msdn.microsoft.com/en-us/library/ms229978(v=vs.85).aspx
答案 1 :(得分:2)
答案是它不能。显然正在发生的是促销活动正在进行中。 (我们意外地发现了这一点)我仍然不知道如何检测促销尝试是否正在发生。在检测到这一点时,这本来就非常有用。
答案 2 :(得分:0)
很难在没有查看代码的情况下提出任何建议,但我的第一个建议是,如果你有一个连接1个SQL服务器,则TransactionScope()是一个开销。
为什么不使用System.Data.SqlClient.SqlTransaction()?
文档说“如果在数据库事务中打开了与远程服务器的连接,则与远程服务器的连接将登记到分布式事务中,并且本地事务将自动提升为分布式事务。”但是,如果你真的只使用一个连接是一个非常奇怪的错误。您确定没有调用任何可以创建与MS SQL,MS MQ或其他需要创建分布式事务的连接的第三方组件吗?
此外,如果您在SQL Server CLR过程中使用TransactionScope(),它将在任何情况下提升事务。
此外,如果您调用从链接的SQL服务器访问表的存储过程,我想这也需要升级。
问题已经很久了,也许你已经知道了答案,可以在这里发布给其他人。谢谢!
答案 3 :(得分:0)
击败了我。
我习惯在“BEGIN TRANSACTION”和“COMMIT”或“ROLLBACK”上手工执行ExecuteNonQuery。
很明显,当一些代码需要工作时,无论是否处于事务中,这都很有效。
答案 4 :(得分:0)
我实际上遇到了同样的问题,它似乎与数据库服务器的规格有关。在执行此代码时,我希望您的dba可以查看该框的CPU利用率。这发生在我们的环境中,因为我们正在对事务中的数据库中的大量行尝试更新操作。这种情况发生在我们最常用的表之一的OLTP数据库上,这会产生锁争用。我发现这个问题引人入胜的是我在堆栈跟踪中看到的超时方面。无论你设置的是什么超时值,无论是在命令上还是作为TransactionScope构造函数的参数,它似乎都没有解决问题。我要解决这个问题的方法是对提交进行分块。希望这有帮助