Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/76.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
当xact_abort处于启用状态时,为什么Sql Server在raiserror之后继续执行?_Sql_Sql Server_Tsql - Fatal编程技术网

当xact_abort处于启用状态时,为什么Sql Server在raiserror之后继续执行?

当xact_abort处于启用状态时,为什么Sql Server在raiserror之后继续执行?,sql,sql-server,tsql,Sql,Sql Server,Tsql,我只是对TSQL中的一些东西感到惊讶。我想如果xact_abort是开着的话 raiserror('Something bad happened', 16, 1); 将停止存储过程(或任何批处理)的执行 但我的ADO.NET错误消息正好相反。我在异常消息中得到了raiserror错误消息,再加上随后发生的故障 这是我的解决方法(这是我的习惯),但似乎没有必要: if @somethingBadHappened begin; raiserror('Something ba

我只是对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时,如果Transact-SQL语句引发运行时错误,则整个事务将终止并回滚

这是否意味着我必须使用显式事务?

这是DesignTM提供的,您可以从SQL Server团队对类似问题的回答中看到:

谢谢你的反馈。根据设计,XACT_ABORT set选项不会影响RAISERROR语句的行为。我们将考虑您的反馈来修改SQLServer未来版本的此行为。 是的,对于一些希望严重性高的
RAISERROR
(如
16
)与SQL执行错误相同的人来说,这有点问题-事实并非如此


您的解决方案正是您需要做的,使用显式事务不会对您想要更改的行为产生任何影响。

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

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

假设我们有一个表[dbo].[Errors]来保存错误 假设我们有一个存储过程[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
--首先让我们构建一个临时表来保存错误
如果(object_id('tempdb..#RAISERRORS')为空)
创建表#RAISERRORS(ErrorNumber int、ErrorMessage varchar(400)、ErrorSeverity int、ErrorState int、ErrorLine int、ErrorProcedure varchar(128));
--这将确定查询的事务级别是否以编程方式确定是否需要开始新事务或创建要回滚到的保存点
声明@tc为int;
设置@tc=@@tracount;
如果(@tc=0)
开始交易;
其他的
保存事务myTransaction;
--将执行try块中的代码
开始尝试
声明@return_值='0';
设置@return_值='0';
声明
@错误编号为int,
@错误消息为varchar(400),
@错误严重性为int,
@ErrorState为int,
@错误行为int,
@ErrorProcedure为varchar(128);
--假设此过程失败。。。
exec@return\u value=[dbo]。[假设失败]
if(@return_值0)
raiserror('这是我的错误消息',17,1);
--错误严重性为17将被视为系统错误。此查询的执行将跳过以下语句,并在begin catch块恢复
如果(@tc=0)
提交事务;
返回(0);
结束尝试
--catch块中的代码将在raiserror(“消息”,17,1)时执行
开始捕捉
选择
@ErrorNumber=错误号(),
@ErrorMessage=错误消息(),
@ErrorSeverity=错误\u严重性(),
@ErrorState=错误状态(),
@ErrorLine=错误线(),
@ErrorProcedure=ERROR_PROCEDURE();
插入#RAISERRORS(错误编号、错误消息、错误严重性、错误状态、错误行、错误过程)
值(@ErrorNumber、@ErrorMessage、@ErrorSeverity、@ErrorState、@ErrorLine、@ErrorProcedure);
--如果我开始交易
如果(@tc=0)
开始
if(XACT_STATE()0)
开始
选择*from#RAISERRORS;
回滚事务;
插入[dbo].[Errors](ErrorNumber、ErrorMessage、ErrorSeverity、ErrorState、ErrorLine、ErrorProcedure)
选择*from#RAISERRORS;
插入[dbo].[Errors](错误编号、错误消息、错误严重性、错误状态、错误行、错误过程)
值(@ErrorNumber、@ErrorMessage、@ErrorSeverity、@ErrorState、@ErrorLine、@ErrorProcedure);
申报表(1);
结束
结束
--如果我没有开始交易
如果(XACT_STATE()=1)
开始
回滚事务myTransaction;
if(object_id('tempdb..#RAISERRORS')不为空)
插入#RAISERRORS(错误编号、错误消息、错误严重性、错误状态、错误行、错误过程)
值(@ErrorNumber、@ErrorMessage、@ErrorSeverity、@ErrorState、@ErrorLine、@ErrorProcedure);
其他的
raiserror(@ErrorMessage、@ErrorSeverity、@ErrorState);
返回(2);
结束
else if(XACT_STATE()=-1)
开始
回滚事务;
if(object_id('tempdb..#RAISERRORS')不为空)
插入#RAISERRORS(错误编号、错误消息、错误严重性、错误状态、错误行、错误过程)
值(@ErrorNumber、@ErrorMessage、@ErrorSeverity、@ErrorState、@ErrorLine、@ErrorProcedure);
其他的
raiserror(@ErrorMessage、@ErrorSeverity、@ErrorState);
返回(3);
结束
端接
结束

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

正如的文档中所指出的,应该使用
THROW
语句,而不是
RAISERROR


这两个人表现得很好。但是当
XACT\u ABORT
设置为ON时,您应该始终使用
THROW
命令。

谢谢。您引用的链接似乎不可用。链接运行正常,如果您需要搜索它,标题为“Have RaiseError work with XACT_ABORT”,作者为“jorundur”,ID:275308链接已失效,它将永远消失在时间的沙漠中。是一个很好的备份-有一个明确的行为。在调用
return
之前,您可能需要调用
回滚事务
。如果您没有2k12(或更高版本),可能需要在catch block中执行一些操作,然后就没有THROW语句了。如果