我需要捕获回滚异常吗

本文关键字:异常 | 更新日期: 2023-09-27 18:27:47

与如何在回滚上捕获异常有关,但不相同

如果我们捕获并显式回滚,那么我们似乎需要尝试/catch包装回滚调用。完全消除try/catch是否仍然是回滚,如果回滚失败,是否仍然发送根本原因异常而不是回滚异常?我试图弄清楚如何复制它,但我不知道如何强制回滚超时。

这是遗留模式:

using (SqlConnection conn = new SqlConnection(ConnectionString))
{
    conn.Open();
    using (SqlTransaction trans = conn.BeginTransaction())
    {
        try
        {
            //do stuff
            trans.Commit();
        }
        catch
        {
            trans.Rollback();
            throw;
        }
    }
}

我需要捕获回滚异常吗

这是我自己在整个职业生涯中使用和看到的一种模式。最近,我遇到了一种情况,我们在生产中发生了异常,堆栈跟踪显示回滚超时,而不是实际发生的异常。我从我的分析中看到,在catch中不使用显式Rollback,而是让using语句来处理它是一种更好的做法

这允许出现正确的根本原因异常,并且事务将在服务器上回滚。为了复制Rollback超时,我创建了一个表和一个过程,并从单元测试中调用事务中的存储过程。

    /****** Object:  Table [dbo].[Table_1]    Script Date: 10/24/2014 12:07:42 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Table_1](
    [id] [int] NULL,
    [GuidTest] [uniqueidentifier] NULL,
    [GuidTest2] [uniqueidentifier] NULL,
    [GuidTest3] [uniqueidentifier] NULL
) ON [PRIMARY]


  /****** Object:  StoredProcedure [dbo].[Test_RollBack]    Script Date: 10/24/2014 12:08:04 PM ******/
/****** Object:  StoredProcedure [dbo].[Test_RollBack]    Script Date: 10/24/2014 12:08:04 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE [dbo].[Test_RollBack]  
AS
BEGIN
    DECLARE @counter int = 1
    while @counter < 3000000
    BEGIN
        INSERT INTO Table_1(id, GuidTest, GuidTest2, GuidTest3)
        VALUES(@counter, newId(), newId(), newId())
        set @counter = @counter + 1
    END

    update Table_1
    SET GuidTest = newid()
END
GO

[TestMethod()]
    public void RollBackTestTimeout()
    {
        using (SqlConnection conn = new SqlConnection("Your ConnectionString"))
        {
            conn.Open();
            using (SqlTransaction trans = conn.BeginTransaction())
            {
                using (SqlCommand cmd = new SqlCommand())
                {
                    try
                    {
                        cmd.Connection = conn;
                        cmd.Transaction = trans;
                        cmd.CommandType = CommandType.StoredProcedure;
                        cmd.CommandText = "Test_RollBack";
                        cmd.ExecuteNonQuery();
                        trans.Commit();
                    }
                    catch
                    {
                        trans.Rollback();
                        throw;
                    }
                }
            }
        }
    }
    [TestMethod()]
    public void RollBackTestTimeout_WithUsing()
    {
        using (SqlConnection conn = new SqlConnection("Your ConnectionString"))
        {
            conn.Open();
            using (SqlTransaction trans = conn.BeginTransaction())
            {
                using (SqlCommand cmd = new SqlCommand())
                {
                    cmd.Connection = conn;
                    cmd.Transaction = trans;
                    cmd.CommandType = CommandType.StoredProcedure;
                    cmd.CommandText = "Test_RollBack";
                    cmd.ExecuteNonQuery();
                    trans.Commit();
                }
            }
        }
    }

对我来说,RollBackTestTimeout测试方法抛出SqlCommandTimeout,但报告回滚超时,而RollBackTestTimeout_WithUsing实际上显示了根本原因异常。因此,根据我的发现,我想说让使用句柄,这样你就可以在以后的生产中调试你的问题。