所以我有一个WCF服务,里面有一个Process()方法。此方法从一个表中读取字节数组(文件),并基本上将该文件中的数据放入多个表中。它只是遍历每一行。它在生产环境中工作了一个月以来一直很好。现在突然间,它间歇地抛出了这个错误:
System.InvalidOperationException:与当前连接关联的事务已完成但尚未处理。必须先处理事务,然后才能使用连接执行SQL语句。
可能会有所帮助的东西: 大约两周前,我们改变了生产网络& DB服务器。我们搬家后,这个错误一直在呕吐。当我们在旧服务器上时,我从未遇到过这个问题。但问题是,这个错误在前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));
}
}
}
Stack Traces之一:
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.<SavePayment>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)
我经历了一些链接:
答案 0 :(得分:8)
首先我会建议在scope.Complete();
末尾添加TransactionScope
,例如:
using (var scope = new TransactionScope())
{
//Your stuff goes here
scope.Complete();
}
必须使用.Complete()
函数在最后一行提交任何事务。
其次如果增加TimeOut
上的machine.config
有效,那么这样做是没有害处的,因为长文件显然需要更多时间。
第三确保在TransactionScope
内调用的任何其他组件都适用于所有正面&amp;消极情景。通过stacktrace,特别是用例似乎有些在函数Tavisca.TramsFileService.ServiceImplementation.TramsFileServiceImpl.ProcessFile(ProcessFileRQ processFileRequest)
还要确保TransactionScope
内的任何底层调用是否使用了某个存储过程,然后存储过程中的任何失败事务也会导致TransactionScope
。
还有一件事,抛出的异常也可能是合法的,因为你在invoice.InvoiceNumber == Guid.Empty
时手动抛出异常,但如果它被处理/捕获或者只是传递给上层,则不会提及。
但首先尝试添加 scope.Complete();
,仅这一点可能是根本原因。
答案 1 :(得分:5)
查看此连接文章,了解.NET ADO库中的问题。
它与必须在客户端(而不是SQL Server)设置的超时有关。
第一个事务超时,但第二个事件抛出错误消息。
您使用的是.NET 4.0框架吗?
这是一篇关于如何在C#代码中设置超时的文章。
http://paulklinker.blogspot.com/2011/08/transaction-timeouts-in-c.html
答案 2 :(得分:1)
因为,正在发生的异常是我建议的超时异常并且它间歇性地发生而没有任何特定的可重现步骤,我们有理由相信这是由于db服务器间歇性地没有正确响应或在指定的超时内(那里)可能是内存问题或突然的重大停机时间。我们不能肯定地说,因为服务器是新设置的。尽管可能有一个原因是在加载和移动时数据中没有处理特定类型的字符但是可能性较小因为应用程序在更改服务器之前已经运行很长时间了)