Sql server 2008 TSQL过程中的错误处理
问题摘要: 我所做的错误处理似乎过于复杂,仍然不能解决所有情况(因为可能存在事务处于不可模仿状态的情况)。我怀疑我:Sql server 2008 TSQL过程中的错误处理,sql-server-2008,sql-server-2005,tsql,error-handling,service-broker,Sql Server 2008,Sql Server 2005,Tsql,Error Handling,Service Broker,问题摘要: 我所做的错误处理似乎过于复杂,仍然不能解决所有情况(因为可能存在事务处于不可模仿状态的情况)。我怀疑我: 错过了一些重要的事情,并且做错了(你能解释一下什么?我该怎么做吗?) 并没有遗漏任何东西——只是必须接受错误处理在SQL Server中仍然是一个巨大的问题 您能否提供更好的解决方案(针对以下情况)? 关于我的情况: 我在SQLServer中有(两个)存储过程,它们是从不同的地方调用的。可以概括为两种情况: 过程是从.NET代码调用的,事务是在SQL过程中生成和处理的 过程在
- 错过了一些重要的事情,并且做错了(你能解释一下什么?我该怎么做吗?)
- 并没有遗漏任何东西——只是必须接受错误处理在SQL Server中仍然是一个巨大的问题
- 将XACT_中止设置为ON;——事务不会因为触发器而变得不可模仿李>
- 声明@PartOfTran位=0;--用于保存状态:1-如果此过程是其他事务的一部分,或0-应启动新事务
- 如果这是其他tran的一部分,则进行保存点。如果不是,则开始事务处理
- 开始尝试块-执行所有操作,如果没有错误,并且这不是嵌套事务,则执行提交。如果是嵌套事务,则将在调用程序中进行提交
- 如果出现错误:如果这是嵌套事务且事务处于可提交状态,则可以回滚到保存点“MyTran”。如果它不是事务的一部分,则回滚名为“MyTran”的事务。在所有其他情况下,只需返回错误代码和消息李>
Create Procedure dbo.usp_MyProcedure
(
-- params here ...
@ReturnCode int out, -- 1 Success, != 1 Error
@ReturnMsg nvarchar(2048) out
)
AS
Begin
Set NoCount ON;
Set XACT_ABORT ON;
Declare @PartOfTran bit = 0;
IF(@@TRANCOUNT > 0)
Begin
SET @PartOfTran = 1;
SAVE TRAN MyTran;
END
Else
BEGIN TRAN MyTran;
Begin Try
-- insert table1
-- update table2
-- ....
IF(@PartOfTran = 0)
COMMIT TRAN MyTran;
Select @ReturnCode = 1, @ReturnMsg = Null;
End Try
Begin Catch
IF (XACT_STATE() = 1 And @PartOfTran = 1) OR @PartOfTran = 0
Rollback Tran MyTran;
Select @ReturnCode = 0, @ReturnMsg = ERROR_MESSAGE();
End Catch
End
其他文献:
从我最喜欢的博客中可以看到:
GOTO _SUCCESS
IF @@ERROR > 0
GOTO _FAIL
因此,如果没有遇到任何错误,它将提交tran
以及tran insert中的所有insert或update语句
GOTO _SUCCESS
IF @@ERROR > 0
GOTO _FAIL
所以当它出错的时候。。它将被送往医院
_FAIL:
ROLLBACK TRAN
SET @ReturnCode = 1
RETURN
你可以在那里设置你所有的返回值
在传输的末尾插入
GOTO _SUCCESS
IF @@ERROR > 0
GOTO _FAIL
因此,如果没有遇到任何错误,它将提交tran
以及tran insert中的所有insert或update语句
GOTO _SUCCESS
IF @@ERROR > 0
GOTO _FAIL
所以当它出错的时候。。它将被送往医院
_FAIL:
ROLLBACK TRAN
SET @ReturnCode = 1
RETURN
你可以在那里设置所有你的返回值在任何情况下,你都无法实现只回滚在
usp\u MyProcedure
中完成的工作的解决方案。考虑最明显的例子:死锁。当您收到异常1205的通知(您被选为死锁受害者)时,事务已经回滚(以允许进行)。随着错误处理的进行,唯一安全的选择是进一步引发并重新抛出,以便调用方有机会做出反应。“未提交事务”只是该主题的一个变体:当调用方启动事务时,错误处理无法以对调用方合理的方式从这种情况中恢复。最好的办法是举起(再扔)。这就是为什么我使用了你在我的博客中看到的模式
在ServiceBroker上下文中考虑这一点意味着没有完全防弹的、异常安全的消息处理例程。如果遇到不可模仿的事务(或在处理catch块时已回滚的事务,如1205 deadlock),则必须回滚整批接收到的消息。在这种情况下,日志记录通常在最外层的捕捉块(通常位于激活程序中)之后进行。下面是如何工作的伪代码:
usp_myActivatedProc
as
@commited = false;
@received = 0;
@errors = 0;
begin transaction
begin try
receive ... into @table;
@received = @@row_count;
foreach message in @table
save transaction
begin try
process one message: exec usp_myProcedure @msg
end try
begin catch
if xact_state()=1
rollback to savepoint
@errors += 1;
-- decide what to do with failed message, log
-- this failure may still be committed (receive won't roll back yet)
else
-- this is a lost cause, re-throw
raiserror
end catch
fetch next @table
endfor
commit
@commited = true;
end try
catch
@error_message = error_message();
if xact_state() != 0
rollback
end catch
if @commited = false
begin
insert into logging 'failed', @received, @error_message
end
在任何情况下,您都无法实现只回滚在
usp\u MyProcedure
中完成的工作的解决方案。考虑最明显的例子:死锁。当您收到异常1205的通知(您被选为死锁受害者)时,事务已经回滚(以允许进行)。随着错误处理的进行,唯一安全的选择是进一步引发并重新抛出,以便调用方有机会做出反应。“未提交事务”只是该主题的一个变体:当调用方启动事务时,错误处理无法以对调用方合理的方式从这种情况中恢复。最好的办法是举起(再扔)。这就是为什么我使用了你在我的博客中看到的模式
在ServiceBroker上下文中考虑这一点意味着没有完全防弹的、异常安全的消息处理例程。如果遇到不可模仿的事务(或在处理catch块时已回滚的事务,如1205 deadlock),则必须回滚整批接收到的消息。在这种情况下,日志记录通常在最外层的捕捉块(通常位于激活程序中)之后进行。下面是如何工作的伪代码:
usp_myActivatedProc
as
@commited = false;
@received = 0;
@errors = 0;
begin transaction
begin try
receive ... into @table;
@received = @@row_count;
foreach message in @table
save transaction
begin try
process one message: exec usp_myProcedure @msg
end try
begin catch
if xact_state()=1
rollback to savepoint
@errors += 1;
-- decide what to do with failed message, log
-- this failure may still be committed (receive won't roll back yet)
else
-- this is a lost cause, re-throw
raiserror
end catch
fetch next @table
endfor
commit
@commited = true;
end try
catch
@error_message = error_message();
if xact_state() != 0
rollback
end catch
if @commited = false
begin
insert into logging 'failed', @received, @error_message
end
嗯,这是一个旧猪圈