与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;
}
}
}
答案 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
实际显示根本原因异常。因此,根据我的发现,我会说使用句柄,以便您以后可以在生产中调试问题。