我有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'
表明数据库没有死锁,因此死锁不是原因。我无法在互联网上找到任何其他资源,这些资源提供了有关异常原因的确切信息。所以有人知道原因是什么或如何找到这个错误的根源?
答案 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计数。
System.Transactions.TransactionInDoubtException
声明:
尝试对事务执行操作时抛出此异常 这是有疑问的。当交易的状态时,交易是有疑问的 交易无法确定。具体来说,最终的结果 这项交易,无论是承诺还是中止,都是不可知的 交易。
尝试此操作时也会抛出此异常 提交事务,事务变成InDoubt。
原因:TransactionScope
期间发生的事情导致其在交易结束时未知状态。
原因:可能有许多不同的原因,但如果没有发布源代码,很难确定您的具体原因。
要检查的事项:
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命令。