【问题标题】:Why am I getting this error suddenly?为什么我突然收到这个错误?
【发布时间】:2014-06-15 06:48:22
【问题描述】:

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

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

可能有帮助的东西: 大约 2 周前,我们更换了生产网络和数据库服务器。这个错误是在我们搬家后才出现的。当我们在旧服务器上时,我从未遇到过这个问题。但问题是,这个错误在最初的 9-10 天内并没有发生。现在它突然间断地发生了。我已经上传了大文件(1k-2.5k 行)并且它们运行良好,并且对于具有 200 行的小得多的文件会引发此错误!而且服务有时会完美地处理同一个文件。

代码sn-p:(要大很多,但类似的操作会重复)

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.<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)

我已经浏览了一些链接:

  1. Link 1
  2. Link 2
  3. Link 3

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

【问题讨论】:

  • 听起来好像有一些错误破坏了交易。你确定你知道没有发生这样的错误吗?我经常看到人们吞下异常。
  • 或者,过早地称为 Complete 方法。会这样吗?
  • @usr:我有服务日志。当我检查日志时,直到最近才出现这种错误。最近出现了多次相同错误的情况
  • @usr:我想我明白你的意思了。我的交易有一个 using 块,在该块的末尾我有 transaction.Coplete()。在中间,如果无法保存任何内容,我有代码抛出错误。会不会是保存的时候报错,事务没有回滚?
  • 根据我的经验,这条消息意味着这件事发生了:try { ExecuteSqlThatFails(); } catch { } ExecuteNextSQL();。第一个错误会杀死反式,但你会吞下它,所以你永远不会发现。下一个 SQL 在没有 SQL Server tran 的失败 .NET tran 下运行。如果不查看导致问题的代码,就不可能解决问题。

标签: c# sql-server wcf transactions transactionscope


【解决方案1】:

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

using (var scope = new TransactionScope())
{
     //Your stuff goes here

     scope.Complete();
}

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

其次如果在machine.config上增加TimeOut是可行的,这样做没有坏处,因为长文件显然需要更多时间。

第三确保在TransactionScope 中调用的任何其他组件都适用于所有正面和负面情况。通过堆栈跟踪,似乎在特定的用例中有些在函数 Tavisca.TramsFileService.ServiceImplementation.TramsFileServiceImpl.ProcessFile(ProcessFileRQ processFileRequest)

内部被破坏

还要确保TransactionScope 中的任何底层调用都使用了某些存储过程,那么存储过程中的任何失败事务也可能导致TransactionScope

还有一件事,抛出的异常也可能是合法的,因为您在 invoice.InvoiceNumber == Guid.Empty 时手动抛出异常,但未提及它是否被处理/捕获或只是传递给上层。

但首先尝试添加 scope.Complete();,仅此一项就可能是根本原因。

【讨论】:

    【解决方案2】:

    查看这篇关于 .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

    【讨论】:

      【解决方案3】:
      1. 使用 scope.Complete();在 finally 块中,这样即使超时 由于数据库服务器需要时间来响应您而发生异常 会完成交易
      2. 另外,增加超时时间,但是 仅当数据库服务器响应时间过长时才可能有所帮助 出于某种原因,但如果数据库服务器变为非 间歇性响应。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-01-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-09
        • 1970-01-01
        相关资源
        最近更新 更多