System.Transactions.TransactionInDoubtException的原因

时间:2014-04-16 12:20:50

标签: sql .net sql-server transactions

我有2个作业在Sql Server数据库中读取和生成数据。每隔一段时间,作业就会因System.Transactions.TransactionInDoubtException而崩溃。确切的堆栈跟踪是:

 Unhandled Exception: 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. ---> System.ComponentModel.Win32Exception: The wait operation timed out. Exitcode: -532462766
    --- End of inner exception stack trace ---
    at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
    at System.Data.SqlClient.TdsParserStateObject.ReadSniError(TdsParserStateObject stateObj, UInt32 error)
    at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
    at System.Data.SqlClient.TdsParserStateObject.TryReadNetworkPacket()
    at System.Data.SqlClient.TdsParserStateObject.TryPrepareBuffer()
    at System.Data.SqlClient.TdsParserStateObject.ReadSniSyncOverAsync()
    at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
    at System.Data.SqlClient.TdsParserStateObject.TryReadByte(Byte& value)
    at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)

我搜索了一下有关MSDTC的一些信息,但我认为这可能不是问题,因为交易应该是本地的,因为作业只能在单个数据库上运行。以下查询:

SELECT cntr_value AS NumOfDeadLocks
  FROM sys.dm_os_performance_counters
 WHERE object_name = 'SQLServer:Locks'
   AND counter_name = 'Number of Deadlocks/sec'
   AND instance_name = '_Total'

表明数据库没有死锁,因此死锁不是原因。我无法在互联网上找到任何其他资源,这些资源提供了有关异常原因的确切信息。所以有人知道原因是什么或如何找到这个错误的根源?

4 个答案:

答案 0 :(得分:10)

即使事务是本地事务,如果您在同一事务范围内打开多个连接,事务仍将升级到MSDTC,根据本文:http://msdn.microsoft.com/en-us/library/ms229978(v=vs.110).aspx

  

导致System.Transactions基础结构的升级   在以下情况下将交易所有权转移到MSDTC:   ...

     
      
  • 在事务中登记了至少两个支持单阶段通知的持久资源。例如,征募   单个连接不会导致事务被提升。   但是,无论何时打开第二个连接到数据库导致   要登记的数据库,System.Transactions基础结构检测到   它是交易中的第二个持久资源,并且   将其升级为MSDTC交易。
  •   

注意:我已经阅读了一些文章,声明这仅适用于SQL 2005,并且SQL 2008+对于MSDTC促销更为明智。这些声明SQL 2008只会在多个连接同时打开 时提升到MSDTC。请参阅:TransactionScope automatically escalating to MSDTC on some machines?

此外,您的内部异常是Timeout(System.Data.SqlClient.SqlException:Timeout expired),而不是Deadlock。虽然两者都与阻止有关,但它们并不是一回事。阻塞导致应用程序停止等待被另一个连接阻塞的资源时发生timeout,以便当前语句可以获取该资源上的锁。当两个不同的连接竞争相同的资源时发生deadlock,并且它们以一种永远无法完成的方式阻塞,除非其中一个连接被终止(这就是为什么死锁错误消息说&#34} ;交易......被选为死锁受害者")。由于您的错误是超时,这解释了为什么您的死锁查询返回0计数。

来自MSDN(http://msdn.microsoft.com/en-us/library/system.transactions.transactionindoubtexception(v=vs.110).aspx)的

System.Transactions.TransactionInDoubtException声明:

  

尝试对事务执行操作时抛出此异常   这是有疑问的。当交易的状态时,交易是有疑问的   交易无法确定。具体来说,最终的结果   这项交易,无论是承诺还是中止,都是不可知的   交易。

     

尝试此操作时也会抛出此异常   提交事务,事务变成InDoubt。

原因:TransactionScope期间发生的事情导致其在交易结束时未知状态。

原因:可能有许多不同的原因,但如果没有发布源代码,很难确定您的具体原因。

要检查的事项:

  1. 如果您使用的是SQL 2005,并且打开了多个连接,则您的交易将被提升为MSDTC交易。
  2. 如果您使用的是SQL 2008+,并且您同时打开了多个连接(即嵌套连接或并行运行的多个ASYNC连接),则该事务将被提升为MSDTC事务。
  3. 如果你有"尝试/捕捉{重试超时/死锁}"在代码中运行的逻辑,当事务在System.Transactions.TransactionScope内时,这可能会导致问题,因为SQL Server在发生超时或死锁时会自动回滚事务。

答案 1 :(得分:2)

我曾经有过这个""交易有疑问"在尝试完成包含对通过实体框架映射的数据库的调用的事务范围时。其中一个通过实体框架调用的是一个存储过程,其中包含一个带有命令" with(tablock, holdlock)"的select语句。似乎对我有用的解决方案是对存储过程返回的结果调用Dispose() - 甚至认为存储过程只是说" Return 0"。这显然释放了资源。

答案 2 :(得分:1)

要在@BateTech的出色回答中提供帮助,以防他人受骗,我必须调试完全相同的方案,就像他描述的方法中存在多个打开的异步连接一样。正在分别等待异步调用,但是方法签名本身为'async void'(!)。关于异步的关键是,如果要执行此操作,则应从入口点一直向下进行。

答案 3 :(得分:1)

我认为没有MSDTC也会发生这种情况。我想我已经在完全不使用MSDTC的系统中发生了这种情况。我认为如果您的数据库连接恰好在某个时刻失败,则会触发该事件。此刻必须使服务已向数据库发送了COMMIT,但随后连接失败,因此该服务无法确定DB是否曾经收到COMMIT命令。