【发布时间】:2012-03-05 10:41:40
【问题描述】:
问题总结:
我进行的错误处理似乎太复杂了,但仍然无法解决所有情况(因为可能存在事务处于不可提交状态的情况)。我怀疑我:
- 错过了一些重要的事情并且做错了(你能解释一下吗?那我应该怎么做?)。
- 没有错过任何事情 - 只需要接受错误处理仍然是 SQL Server 中的大问题。
您能否提供更好的解决方案(针对以下描述的情况)?
关于我的情况:
我在 SQL Server 中有(几个)存储过程,从不同的地方调用。可以概括为两种情况:
- 从 .NET 代码调用过程,在 SQL 过程中创建和处理事务
- 过程在其他过程中被调用(更具体地说是在 Service Broker 激活过程中),因此事务由外部过程处理。
我这样做了,该过程返回结果(1 表示成功,0 表示失败)+ 在出现错误时返回用于记录目的的消息。
程序内部:
- 将 XACT_ABORT 设置为 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
其他文献:
从我最喜欢的博主那里看到:
- sommarskog - 但我不喜欢“outer_sp”的行“IF @@trancount > 0 ROLLBACK TRANSACTION”,因为在我的情况下,外部过程可以在事务中调用,所以在这种情况下,我有“事务计数之后EXECUTE 表示 BEGIN 和 COMMIT 语句的数量不匹配。以前的计数 = 1,当前的计数 = 0。"
- rusanu - 实际上和我在这里写的几乎一样(也许想法来自那篇博客文章 - 我根据我所读到的关于这个主题的所有内容编写了我的解决方案)。这篇博文仍然没有解决我应该如何处理不可提交的交易。这是 Service Broker 的问题。如果我必须回滚不可提交的事务,如何正确记录错误消息?我对此有一些想法,但所有这些似乎都是解决方法而不是优雅的解决方案。
【问题讨论】:
标签: sql-server-2008 sql-server-2005 tsql error-handling service-broker