【问题标题】:Reason for System.Transactions.TransactionInDoubtExceptionSystem.Transactions.TransactionInDoubtException 的原因
【发布时间】:2014-05-31 07:39:15
【问题描述】:

我有 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'

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

【问题讨论】:

    标签: sql .net sql-server transactions


    【解决方案1】:

    就我而言,我只是忘记关闭我的DataReader 连接。

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        【解决方案3】:

        为了添加@BateTech 的出色答案以防万一这对其他人有所帮助,我必须调试完全相同的场景,正如他所描述的那样,在一个方法中发生了多个打开的异步连接。异步调用正在单独等待,但方法签名本身是“async void”(!)。异步的关键在于,如果你要这样做,你应该从入口点一直向下进行。

        【讨论】:

          【解决方案4】:

          当我试图完成一个事务范围时,我曾经遇到过这个“事务有问题”,该范围包括对通过实体框架映射的数据库的调用。通过实体框架的调用之一是对一个存储过程,该过程包含一个 select 语句命令“with(tablock, holdlock)”。似乎对我有用的解决方案是在存储过程返回的结果上调用Dispose()——即使存储过程只是说“Return 0”。这显然释放了资源。

          【讨论】:

            【解决方案5】:

            即使事务是本地的,如果在同一个事务范围内打开多个连接,事务仍然会升级到 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:超时已过期),而不是Deadlock。虽然两者都与阻塞有关,但它们并不是一回事。当阻塞导致应用程序停止等待被另一个连接阻塞的资源时,会发生timeout,以便当前语句可以获得对该资源的锁定。 deadlock 当两个不同的连接竞争相同的资源时发生,并且它们以一种它们永远无法完成的方式阻塞,除非其中一个连接被终止(这就是为什么死锁错误消息说“事务......已被选为死锁受害者”)。由于您的错误是超时,这解释了为什么您的死锁查询返回 0 计数。

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

            尝试对事务执行操作时会引发此异常 这是有疑问的。当交易的状态存在疑问时 交易无法确定。具体来说,最终结果 事务,无论是提交还是中止,都不会因此而为人所知 交易。

            当尝试 提交事务,事务变为 InDoubt。

            原因:在TransactionScope 期间发生了一些事情,导致它在事务结束时的状态未知。

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

            检查事项:

            1. 如果您使用的是 SQL 2005,并且打开了多个连接,您的事务将被提升为 MSDTC 事务。
            2. 如果您使用的是 SQL 2008+,并且同时打开了多个连接(即嵌套连接或并行运行的多个 ASYNC 连接),则该事务将被提升为 MSDTC 事务。
            3. 如果您的代码中运行“try/catch{retry if timeout/deadlock}”逻辑,那么当事务位于 System.Transactions.TransactionScope 内时,这可能会导致问题,因为 SQL Server 自动滚动的方式发生超时或死锁时返回事务。

            【讨论】:

            • 感谢您的回复。实际上,错误神奇地不再发生,所以我认为这是由异常重负载引起的锁定资源,导致超时并将事务置于 InDoubt 状态,正如您已经解释的那样。无论如何,你的回复让我对可能的原因有了更多的了解。谢谢你。
            猜你喜欢
            • 2014-11-13
            • 2017-04-10
            • 1970-01-01
            • 2015-12-30
            • 1970-01-01
            • 2011-07-30
            • 2014-10-17
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多