我需要捕获回滚异常吗?

时间:2014-10-24 16:20:33

标签: c# ado.net

How to catch exception on RollBack

相关但不相同

如果我们捕获并明确回滚,我们需要try/catch wrap the rollback call。消除try / catch完全仍然会回滚,如果回滚失败,仍然会发送根本原因异常而不是回滚异常吗?我试图找出如何复制它,但我不知道如何强制回滚超时。

这是传统模式:

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

1 个答案:

答案 0 :(得分:3)

这是我自己在整个职业生涯中使用过的模式。最近我遇到了一种情况,我们在生产中发生异常,堆栈跟踪显示Rollback超时而不是发生的实际异常。我从我的分析中看到,更好的做法是不在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实际显示根本原因异常。因此,根据我的发现,我会说使用句柄,以便您以后可以在生产中调试问题。