sql - System.Transactions.TransactionInDoubtException 的原因

标签 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'

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

最佳答案

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

An escalation that results in the System.Transactions infrastructure transferring the ownership of the transaction to MSDTC happens when: ...

  • At least two durable resources that support single-phase notifications are enlisted in the transaction. For example, enlisting a single connection with does not cause a transaction to be promoted. However, whenever you open a second connection to a database causing the database to enlist, the System.Transactions infrastructure detects that it is the second durable resource in the transaction, and escalates it to an MSDTC transaction.

注意:我读过一些文章,指出这仅适用于 SQL 2005,而 SQL 2008+ 在 MSDTC 升级方面更加智能。这些规定仅当同时打开多个连接时,SQL 2008 才会升级为 MSDTC。请参阅:TransactionScope automatically escalating to MSDTC on some machines?

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

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

System.Transactions.TransactionInDoubtException 指出:

This exception is thrown when an action is attempted on a transaction that is in doubt. A transaction is in doubt when the state of the transaction cannot be determined. Specifically, the final outcome of the transaction, whether it commits or aborts, is never known for this transaction.

This exception is also thrown when an attempt is made to commit the transaction and the transaction becomes InDoubt.

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

原因:可能有多种不同的原因,但在不发布源代码的情况下很难确定具体原因。

要检查的事项:

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

关于sql - System.Transactions.TransactionInDoubtException 的原因,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23109323/

相关文章:

sql - SELECT DISTINCT 非常慢

sql - 查询以获取总行数和不同行数之间的差异

asp.net - 无法在 UpdatePanel 中下载文件

c# - C# 赋值变量时的异常处理

sql - 纯 SQL、Yii Active Record 或混合

c# - 如何按长度的字母顺序对字符串数组进行排序?

sql - 唯一标识符 PK : Is a SQL Server heap the right choice?

sql - 无法执行存储过程

sql-server - Sqoop从hive导出到sql被卡住

mysql - 选择不同的记录,同时从 MySQL 中选择第一次出现的记录