为什么我突然收到这个错误?

所以我有一个WCF服务,里面有一个Process()方法。 此方法从一个表中读取字节数组(文件),并基本上将该文件中的数据放入多个表中。 它只是遍历每一行。 它在生产环境中工作了一个月以来一直很好。 现在突然间,它间歇地抛出这个错误:

System.InvalidOperationException:与当前连接关联的事务已完成但尚未处理。 必须先处理事务,然后才能使用连接执行SQL语句。

可能有所帮助的东西:大约两周前,我们更换了生产网络和数据库服务器。 我们搬家后,这个错误一直在呕吐。 当我们在旧服务器上时,我从未遇到过这个问题。 但问题是,这个错误在前9-10天没有发生。 现在它突然间歇地发生了。 我已经上传了大文件(1k-2.5k行)并且它们工作正常,并且这个错误会引发更小的200行文件! 并且服务有时会完美地处理相同的文件。

代码片段:(它更大,但重复类似的操作)

using (var scope = new TransactionScope()) { // loop through each row/invoice foreach (var row in Rows) { Invoice invoice = (Invoice)CreateObjectWithConstantData(typeof(Invoice), doc, applicationName); invoice = (Invoice)FillObjectWithUserData(invoice, row, -1, -1, string.Empty); invoice.InvoiceNumber = InvoiceDBImpl.SaveInvoice(invoice, processFileRequest.RunId); if (invoice.InvoiceNumber == Guid.Empty) { throw new DataAccessException(string.Format(Messages.ErrorSavingInvoice, invoice.ReceiptId, invoice.ProductID)); } } } 

堆栈跟踪之一:

  at System.Data.SqlClient.TdsParser.TdsExecuteRPC(_SqlRPC[] rpcArray, Int32 timeout, Boolean inSchema, SqlNotificationRequest notificationRequest, TdsParserStateObject stateObj, Boolean isCommandProc) at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result) at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(DbAsyncResult result, String methodName, Boolean sendToPipe) at System.Data.SqlClient.SqlCommand.ExecuteNonQuery() at System.Data.SqlClient.SqlCommand.ExecuteNonQuery() at System.Data.Linq.SqlClient.SqlProvider.Execute(Expression query, QueryInfo queryInfo, IObjectReaderFactory factory, Object[] parentArgs, Object[] userArgs, ICompiledSubQuery[] subQueries, Object lastResult) at System.Data.Linq.SqlClient.SqlProvider.ExecuteAll(Expression query, QueryInfo[] queryInfos, IObjectReaderFactory factory, Object[] userArguments, ICompiledSubQuery[] subQueries) at System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq.Provider.IProvider.Execute(Expression query) at System.Data.Linq.DataContext.ExecuteMethodCall(Object instance, MethodInfo methodInfo, Object[] parameters) at Tavisca.TramsFileService.DataAccess.TramsDBDataContext.SaveTramsPayment(Nullable`1 paymentDate, String paymentType, Nullable`1 totalAmount, String bankAccount, String paymentMethod, String branch, String remarks, String creditCardLast4, String payeeName, String profileNumber, Nullable`1& paymentId) at Tavisca.TramsFileService.DataAccess.PaymentDBImpl.c__DisplayClass1.b__0(TramsDBDataContext dc) at Tavisca.TramsFileService.DataAccess.SystemDataContext.PerformOperation(Action`1 action) at Tavisca.TramsFileService.DataAccess.PaymentDBImpl.SavePayment(Payment payment) at Tavisca.TramsFileService.Core.TramsFileController.ProcessFile(ProcessFileRQ processFileRequest) at Tavisca.TramsFileService.ServiceImplementation.TramsFileServiceImpl.ProcessFile(ProcessFileRQ processFileRequest) 

我经历了一些链接:

  1. 链接1
  2. 链接2
  3. 链接3

他们都建议在machine.config上增加TimeOut,但我不确定为什么它有时会起作用而在其他时候不起作用。 这不应该一致吗?

首先 ,我建议添加scope.Complete();TransactionScope末尾像:

 using (var scope = new TransactionScope()) { //Your stuff goes here scope.Complete(); } 

必须使用.Complete()函数在最后一行提交任何事务。

其次,如果在machine.config上增加TimeOut ,那么这样做没有什么害处,因为长文件显然需要更多时间。

第三,确保在TransactionScope内部调用的任何其他组件都适用于所有正面和负面场景。 通过stacktrace,特别是用例似乎有些内容破坏了函数Tavisca.TramsFileService.ServiceImplementation.TramsFileServiceImpl.ProcessFile(ProcessFileRQ processFileRequest)

还要确保TransactionScope的任何底层调用是否使用了某个存储过程,然后存储过程中的任何失败事务也会导致TransactionScope

还有一件事 ,抛出的exception也可能是合法的,因为你在invoice.InvoiceNumber == Guid.Empty时手动抛出exception,但如果它被处理/捕获或者只是传递给上层,则不提及。

但首先尝试添加scope.Complete(); ,这可能是根本原因。

查看此连接文章,显示.NET ADO库中的问题。

http://connect.microsoft.com/VisualStudio/feedback/details/266095/transactionscope-timeout-issue-with-sqlconnection-and-ltm-some-operations-are-not-rolled-back

它与必须在客户端(而不是SQL Server)设置的超时有关。

第一个事务超时但第二个事务抛出错误消息。

您使用的是.NET 4.0框架吗?

这是一篇关于如何在C#代码中设置超时的文章。

http://paulklinker.blogspot.com/2011/08/transaction-timeouts-in-c.html

  1. 使用scope.Complete(); 在finally块中,以便即使由于db服务器花时间响应而发生超时exception,您也可以完成事务
  2. 此外,增加超时,但这可能仅在数据库服务器由于某种原因需要太长时间才能响应时才有用,但如果数据库服务器间歇性地无响应则可能无效。

因为,正在发生的exception是我建议的超时exception并且它间歇性地发生而没有任何特定的可重现步骤,我们有理由相信这是由于db服务器间歇性地没有正确响应或在指定的超时内(可能存在内存)因为服务器是新设置的,所以我们不能肯定地说这个问题。虽然在加载和移动时数据中没有处理特定类型的字符可能有原因但是自应用程序以来可能不太可能在更改服务器之前已经启动并运行了很长时间)