gpt4 book ai didi

c# - 围绕 SqlTransaction 回滚的异常处理

转载 作者:太空狗 更新时间:2023-10-30 00:22:29 26 4
gpt4 key购买 nike

我有两个存储过程,我想在一个事务中执行它们。由于各种原因,我需要在我的应用程序代码中而不是在数据库中处理事务。

目前,我的代码如下所示:

try
{
using (SqlConnection conn = Connection())
{
conn.Open();

using (SqlTransaction sqlTrans = conn.BeginTransaction())
{
try
{
using (SqlCommand cmd1 = new SqlCommand("Stored_Proc_1", conn, sqlTrans))
{
cmd1.CommandType = CommandType.StoredProcedure;
cmd1.ExecuteNonQuery();
}

using (SqlCommand cmd2 = new SqlCommand("Stored_Proc_2", conn, sqlTrans))
{
cmd2.CommandType = CommandType.StoredProcedure;
cmd2.ExecuteNonQuery();
}

sqlTrans.Commit();
}
catch
{
sqlTrans.Rollback();

throw;
}

}

conn.Close();
}
}

catch (SqlException ex)
{
// exception handling and logging code here...
}

当其中一个存储过程引发错误时,我看到的异常消息如下所示:

Error message from raiserror within stored procedure.
Transaction count after EXECUTE indicates that a COMMIT or ROLLBACK TRANSACTION statement is missing. Previous count = 1, current count = 0.

这是有道理的,因为在第一次捕获时,事务还没有回滚。

但我想要一个“干净”的错误(没有 tran count 消息 - 我对此不感兴趣,因为我正在回滚事务)用于我的异常处理代码。有没有办法重组我的代码来实现这个目标?

编辑:

我的存储过程的基本结构如下所示:

create proc Stored_Proc_1
as

set nocount on

begin try
begin transaction

raiserror('Error raised by Stored_Proc_1', 16, 1)

commit

end try
begin catch
if (@@trancount > 0) rollback

declare @ErrMsg nvarchar(4000), @ErrSeverity int, @ErrProc sysname, @ErrLine varchar(10)
select @ErrMsg = ERROR_MESSAGE(), @ErrSeverity = ERROR_SEVERITY(), @ErrProc = ERROR_PROCEDURE(), @ErrLine = ERROR_LINE()

-- log the error
-- sql logging code here...

raiserror(@ErrMsg, @ErrSeverity, 1)
end catch

更新:我已经从我的存储过程中取出事务处理,这似乎已经解决了问题。显然我做错了 - 但我仍然想知道如何做对。从存储过程中删除事务是最好的解决方案吗?

最佳答案

好吧,conn.Close() 无论如何都可以 - 它会被 using 关闭(如果你想一想,很奇怪我们只Close() 发生异常后关闭它)。

您的存储过程是否在其内部执行任何事务代码(未回滚/提交)?听起来就是问题所在...?如果有的话,错误消息向我暗示其中一个存储过程正在执行 COMMIT,即使它没有启动事务 - 可能是由于(不正确的)方法:

-- pseduo-TSQL
IF @@TRANCOUNT = 0 BEGIN TRAN
-- ...
IF @@TRANCOUNT > 0 COMMIT TRAN -- or maybe = 1

(如果您在 TSQL 中执行条件事务,您应该跟踪(通过 bool 标志)您是否创建了事务 - 如果您创建了事务,则仅COMMIT)

另一种选择是使用 TransactionScope - 更易于使用(您不需要针对每个命令等设置它),但稍微效率较低:

using(TransactionScope tran = new TransactionScope()) {
// create command, exec sp1, exec sp2 - without mentioning "tran" or
// anything else transaction related

tran.Complete();
}

(注意没有回滚等;Dispose()(通过 using)将在需要时进行回滚。

关于c# - 围绕 SqlTransaction 回滚的异常处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/943876/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com