我需要捕获回滚异常吗
本文关键字:异常 | 更新日期: 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
实际上显示了根本原因异常。因此,根据我的发现,我想说让使用句柄,这样你就可以在以后的生产中调试你的问题。