如何检测回滚已经发生? [英] How to detect that rollback has occurred?

查看:34
本文介绍了如何检测回滚已经发生?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm hunting down a bug in a large business application, where business processes are failing but partially persisted to the database. To make things harder to figure out, the process fails only once every few weeks, with hundreds of thousands successfully processed between every failure. The error frequency seems to go up when concurrency/number of worker processes goes up.

到目前为止,我们已经能够通过该程序重现我们所看到的内容.(.NET 4.7.1 框架)

So far, we've been able to recreate what we're seeing with this program. (.NET 4.7.1 framework)

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(),它只是在我的示例中作为重现错误消息和行为的手段.但是,如果我们的任何第三方库进行此调用,我想抛出异常并尽快退出.最好在应用层.

Our production code does not explicitly make calls to transaction.Rollback(), it is simply in my example as the means to reproduce the error message and behavior. But if any of our third party libraries makes this call, I would like to throw exception and exit as soon as possible. Preferably in the application layer.

我如何检测对 Rollback() 的调用已经完成?我真的不想在没有确定 transactionScope 能够完成它的工作的情况下进行 crud 操作.

How can I detect that the call to Rollback() has been made? I really do not want to make crud operations without being sure that the transactionScope is able to do it's job.

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

My unwanted "rollback" was caused by a bug somewhere in the connection sharing mechanism of .Net. The bug is reproduced on all .Net Framework version between 4.5.1 and 4.8, and also on the new System.Data.SqlClient package.

问题已添加到 System.Data.SqlClient 存储库.

推荐答案

不同的事务 API 不能一起工作.所以你在这里处于危险的境地.

The different transaction APIs don't all work together. So you're in dangerous territory here.

如何检测是否调用了 Rollback()?

How can I detect that the call to Rollback() has been made?

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

select @@trancount should always tell you. The rollback will revert @@trancount to 0.

这篇关于如何检测回滚已经发生?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆