当前位置:  开发笔记 > 数据库 > 正文

当xact_abort打开时,为什么Sql Server在raiserror之后继续执行?

如何解决《当xact_abort打开时,为什么SqlServer在raiserror之后继续执行?》经验,为你挑选了4个好方法。

我对TSQL中的某些东西感到惊讶.我认为,如果xact_abort打开,调用类似的东西

raiserror('Something bad happened', 16, 1);

将停止执行存储过程(或任何批处理).

但我的ADO.NET错误消息恰恰相反.我在异常消息中收到了raiserror错误消息,以及之后发生的下一个错误消息.

这是我的解决方法(无论如何这是我的习惯),但它似乎不应该是必要的:

if @somethingBadHappened
    begin;
        raiserror('Something bad happened', 16, 1);
        return;
    end;

文档说这个:

当SET XACT_ABORT为ON时,如果Transact-SQL语句引发运行时错误,则终止并回滚整个事务.

这是否意味着我必须使用显式交易?



1> Philip Rieck..:

这是By Design TM,正如您可以在Connect上看到的SQL Server团队对类似问题的回答:

感谢您的反馈意见.根据设计,XACT_ABORT设置选项不会影响RAISERROR语句的行为.我们将考虑您的反馈,以便为将来的SQL Server版本修改此行为.

是的,对于一些希望RAISERROR具有高严重性(例如16)与SQL执行错误相同的人来说,这是一个问题- 事实并非如此.

您的解决方法只是您需要做的事情,使用显式事务对您要更改的行为没有任何影响.


链接工作正常,如果你需要搜索它,标题"让RAISERROR与XACT_ABORT一起工作",作者"jorundur",ID:275308

2> ninegrid..:

如果使用try/catch块,则严重性为11-19的raiserror错误号将导致执行跳转到catch块.

任何高于16的严重性都是系统错误.要演示以下代码,请设置try/catch块并执行我们假设将失败的存储过程:

假设我们有一个表[dbo].[错误]保存错误假设我们有一个存储过程[dbo].[AssumeThisFails],当我们执行它时会失败

-- first lets build a temporary table to hold errors
if (object_id('tempdb..#RAISERRORS') is null)
 create table #RAISERRORS (ErrorNumber int, ErrorMessage varchar(400), ErrorSeverity int, ErrorState int, ErrorLine int, ErrorProcedure varchar(128));

-- this will determine if the transaction level of the query to programatically determine if we need to begin a new transaction or create a save point to rollback to
declare @tc as int;
set @tc = @@trancount;
if (@tc = 0)
 begin transaction;
else
 save transaction myTransaction;

-- the code in the try block will be executed
begin try
 declare @return_value = '0';
 set @return_value = '0';
 declare
  @ErrorNumber as int,
  @ErrorMessage as varchar(400),
  @ErrorSeverity as int,
  @ErrorState as int,
  @ErrorLine as int,
  @ErrorProcedure as varchar(128);


 -- assume that this procedure fails...
 exec @return_value = [dbo].[AssumeThisFails]
 if (@return_value <> 0)
  raiserror('This is my error message', 17, 1);

 -- the error severity of 17 will be considered a system error execution of this query will skip the following statements and resume at the begin catch block
 if (@tc = 0)
  commit transaction;
 return(0);
end try


-- the code in the catch block will be executed on raiserror("message", 17, 1)
begin catch
  select
   @ErrorNumber = ERROR_NUMBER(),
   @ErrorMessage = ERROR_MESSAGE(),
   @ErrorSeverity = ERROR_SEVERITY(),
   @ErrorState = ERROR_STATE(),
   @ErrorLine = ERROR_LINE(),
   @ErrorProcedure = ERROR_PROCEDURE();

  insert #RAISERRORS (ErrorNumber, ErrorMessage, ErrorSeverity, ErrorState, ErrorLine, ErrorProcedure)
   values (@ErrorNumber, @ErrorMessage, @ErrorSeverity, @ErrorState, @ErrorLine, @ErrorProcedure);

  -- if i started the transaction
  if (@tc = 0)
  begin
   if (XACT_STATE() <> 0)
   begin
     select * from #RAISERRORS;
    rollback transaction;
    insert into [dbo].[Errors] (ErrorNumber, ErrorMessage, ErrorSeverity, ErrorState, ErrorLine, ErrorProcedure)
     select * from #RAISERRORS;
    insert [dbo].[Errors] (ErrorNumber, ErrorMessage, ErrorSeverity, ErrorState, ErrorLine, ErrorProcedure)
     values (@ErrorNumber, @ErrorMessage, @ErrorSeverity, @ErrorState, @ErrorLine, @ErrorProcedure);
    return(1);
   end
  end
  -- if i didn't start the transaction
  if (XACT_STATE() = 1)
  begin
   rollback transaction myTransaction;
   if (object_id('tempdb..#RAISERRORS') is not null)
    insert #RAISERRORS (ErrorNumber, ErrorMessage, ErrorSeverity, ErrorState, ErrorLine, ErrorProcedure)
     values (@ErrorNumber, @ErrorMessage, @ErrorSeverity, @ErrorState, @ErrorLine, @ErrorProcedure);
   else
    raiserror(@ErrorMessage, @ErrorSeverity, @ErrorState);
   return(2); 
  end
  else if (XACT_STATE() = -1)
  begin
   rollback transaction;
   if (object_id('tempdb..#RAISERRORS') is not null)
    insert #RAISERRORS (ErrorNumber, ErrorMessage, ErrorSeverity, ErrorState, ErrorLine, ErrorProcedure)
     values (@ErrorNumber, @ErrorMessage, @ErrorSeverity, @ErrorState, @ErrorLine, @ErrorProcedure);
   else
    raiserror(@ErrorMessage, @ErrorSeverity, @ErrorState);
   return(3);
  end
 end catch
end



3> 小智..:

RETURN之后立即使用RAISERROR(),它不会进一步执行该程序.


你可能想在调用`return`之前调用`rollback transaction`.

4> Möoz..:

正如在MSDN上指出的那样,THROW应该使用该语句来代替RAISERROR.

两者表现略有不同.但是当XACT_ABORT设置为ON时,则应始终使用该THROW命令.


如果你没有2k12(或者当它出来时是上面的那个),那么就没有THROW声明了.
推荐阅读
ERIK又
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有