如何检测回滚是否发生?

8
我正在追踪一个大型商业应用程序中的错误,其中业务流程失败但部分保留在数据库中。让事情更难以弄清楚的是,每隔几周流程才会失败一次,在每次失败之间都成功处理了数十万个流程。当并发/工作进程数量增加时,错误频率似乎会提高。
到目前为止,我们已经能够使用此程序重现所见到的问题。(.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能够正常工作的情况下进行crud操作。

更新1

我不想要的“回滚”是由.Net连接共享机制中某处的bug引起的。该bug在所有.Net Framework版本(4.5.1至4.8)以及新的System.Data.SqlClient package上都可以重现。

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


Transaction.Current.TransactionInformation.Status 属性直到程序失败之前都是 Active - stalskal
也许你在 SQL Server 中遇到了死锁问题,但你可以通过扩展事件和操作系统的资源监视器来监控 SQL Server 的死锁和事务,或者使用像 Apex SQL Monitor 这样的优秀工具。 - Mahdi Rahimi
SQL Server 跟踪事务和回滚等操作... 您可以查询它所执行的操作。 - Keith Nicholas
1个回答

2

这些不同的事务API并不完全兼容,因此您在这里处于危险地带。

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

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

最初的回答:

由于不同的事务API并不完全兼容,因此在使用时需要注意。如果需要检测是否调用了 Rollback(),可以使用 select @@trancount 命令来查询。该命令会返回当前事务嵌套层数,回滚操作会将其恢复为 0。


记录@@trancount有助于我找到了根本原因。当不一致性发生时, using (var transaction = new TransactionScope() {之后,@@trancount立即变为0。所以没有回滚操作,但是在这里存在其他问题。 - stalskal
1
我的问题实际上是由于.Net连接共享机制中的某个bug引起的。https://github.com/dotnet/SqlClient/issues/237 - stalskal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接