【问题标题】:How to detect that rollback has occurred?如何检测是否发生了回滚?
【发布时间】:2019-09-02 21:13:19
【问题描述】:

我正在寻找大型业务应用程序中的一个错误,其中业务流程失败但部分保留到数据库中。为了让事情更难弄清楚,这个过程每隔几周才会失败一次,每次失败之间都会成功处理数十万次。当并发/工作进程数量增加时,错误频率似乎会增加。

到目前为止,我们已经能够通过这个程序重新创建我们所看到的内容。 (.NET 4.7.1 框架)

using (var transactionScope = new TransactionScope(TransactionScopeOption.RequiresNew))
{
    using (var sqlConnection = new SqlConnection("Server=localhost;Database=Database1;Trusted_Connection=True"))
    {
        sqlConnection.Open();

        // Doing some unwanted nested manual transaction and rolling it back
        var transaction = sqlConnection.BeginTransaction();
        new SqlCommand($"INSERT INTO TestTable VALUES('This will be rolled back}')", sqlConnection).ExecuteNonQuery();

        transaction.Rollback();

        // Now doing some work with the DB.
        // You might expect it to become a part of transactionScope, but that is NOT the case!
        // So this command will actually succeed, with data written to the DB.
        new SqlCommand($"INSERT INTO TestTable VALUES('This will be inserted')", sqlConnection).ExecuteNonQuery();

        // Doing something which promotes the local transaction to a distributed transaction.
        using (var sqlConnection2 = new SqlConnection("Server=localhost;Database=Database2;Trusted_Connection=True"))
        {
            // The program will fail here, with message "The transaction has aborted, Failure while attempting to promote transaction."
            sqlConnection2.Open();

            new SqlCommand($"INSERT INTO TestTable2 VALUES('We will never come this far')", sqlConnection2).ExecuteNonQuery();

        }
    }
    transactionScope.Complete();
}

我们的生产代码没有显式调用transaction.Rollback(),它只是在我的示例中作为重现错误消息和行为的手段。但是,如果我们的任何第三方库进行此调用,我想尽快抛出异常并退出。最好在应用层。

我怎样才能检测到对Rollback() 的调用已进行?我真的不想在不确定transactionScope 是否能够完成工作的情况下进行粗鲁操作。

更新 1

我不需要的“回滚”是由 .Net 的连接共享机制中的某个错误引起的。该错误在 4.5.1 和 4.8 之间的所有 .Net Framework 版本以及新的 System.Data.SqlClient package 上重现。

一个issue has been added to the System.Data.SqlClient repository

【问题讨论】:

  • 在程序失败之前,Transaction.Current.TransactionInformation.Status 属性是 Active
  • 可能你的sql server有死锁,你可以用os中的扩展事件和资源监视器或者apex sql monitor等很多好工具来监控sql server的死锁和事务
  • sql server 跟踪事务和回滚等......你可以查询它做了什么

标签: c# sql-server msdtc


【解决方案1】:

不同的事务 API 不能一起工作。所以你在这里很危险。

如何检测到已经调用了 Rollback()?

select @@trancount 应该总是告诉你。回滚会将@@trancount 恢复为 0。

【讨论】:

  • 记录 @@trancount 帮助我找到了根本原因。当出现不一致时,@@trancount 紧跟在using (var transaction = new TransactionScope() { 之后的0。所以没有进行回滚,但这里还有其他问题。
  • 我的问题实际上是由.Net的连接共享机制中的某个地方的错误引起的。 github.com/dotnet/SqlClient/issues/237
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-04-05
  • 2016-03-04
  • 2012-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-08
相关资源
最近更新 更多