我对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 票数:45

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

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

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

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

===============>>#2 票数:23

如果使用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 票数:22

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

===============>>#4 票数:13

正如在MSDN上指出的那样,应该使用THROW语句而不是RAISERROR

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

  ask by Eric Z Beard translate from so

未解决问题?本站智能推荐:

1回复

XACT_ABORT不会在SQL Server 2012上回滚事务

这是我编写的一个简单测试。 据我了解,由于我具有SET XACT_ABORT ON ,所以当第二个创建过程失败时,整个事务将回滚。 取而代之的是,只有发生错误的事物(第一个创建过程)才被回滚,而最后一个创建过程执行得很好。 然后,我收到一条消息, The COMMIT TRANSAC
1回复

使用SET XACT_ABORT ON时需要显式事务语句吗?

如果在CREATE PROCEDURE语句中使用SET XACT_ABORT ON ,是否必须将所有语句包装在显式事务语句下: BEGIN TRANSACTION和COMMIT ? 还是在执行错误的情况下不管执行这些操作, SET XACT_ABORT ON终止过程执行吗?
2回复

T-SQL:如何从存储过程返回0行,以及如何使用XACT_ABORT和TRY / CATCH

我正在写一个存储过程,我想在出现故障时返回0条记录。 我似乎无法弄清楚如何只返回0行? 我用SELECT NULL但这返回1列有NULL行1列1,我也试图不指定任何SELECT在我的错误代码路径声明,但测试的价值时, @@ROWCOUNT后调用的SP,返回1.我认为这可能是因为@@ROWCO
1回复

如果您不在事务中,SET XACT_ABORT ON是否在存储过程中执行任何操作?

如果您不在事务中, SET XACT_ABORT ON是否在存储过程中执行任何操作? 我问,因为我的存储过程似乎以某种方式回滚插入语句,即使存储过程中失败的部分不在事务中。 正在向上推动表的标识,但是在存储过程返回后插入的行不存在,尽管插入是无条件的而不是在事务内。 或者是否有任何
2回复

SET XACT_ABORT ON被忽略,事务继续(SQL Server 2008 R2)

也许我缺少了一些东西,但是即使下面的RAISERROR的严重性为16(根据文档),事务仍将提交,就像XACT_ABORT ON无效一样。 呼唤 产生 消息50000,级别16,状态2,过程RemoveMember,第20行 指定的用户不是该组的管理员 消息500
2回复

如何在SQL Server事务中设置“SET XACT_ABORT ON”?

我想在SQL Server 2008R2存储过程中使用事务设置SET XACT_ABORT ON ,因此在创建脚本中执行此操作: 成功创建后,我通过单击“修改”存储过程选项检查事务,并在生成的ALTER PROCEDURE脚本中,我看不到SET XACT_ABORT ON : 我
1回复

从SQL Server 8到11的RAISERROR转换

我已将数据库从旧的旧版MSSQL Server 2000(SQL Server 8)移至SQL Server 11,并且在多个触发器中收到了一些错误。 它们是这样形成的。 和 因此,经过一番阅读后,我发现这是一个已知的更改,但是我找不到任何众所周知的解决方案。 起初我
9回复

SQL Server中的T-SQL STOP或ABORT命令

Microsoft SQL Server T-SQL中是否有命令告诉脚本停止处理? 我有一个脚本,我想保留用于存档目的,但我不希望任何人运行它。
1回复

SQL Server SET XACT_ABORT ON与TRY…CATCH在存储过程中的块

我正在开发游戏数据库。 我有一个存储过程,由游戏客户端在传送,登录,注销,死亡等过程中执行。 游戏客户端是硬编码的,不能由我编辑。 我正在执行我的程序中的操作,例如,如果角色登录到游戏,然后将项目添加到角色的清单中。 对于每种不同类型的过程,我都有IF块,并且每个“ IF”块中都
1回复

为什么SQL Server默认XACT_ABORT为OFF?可以在全球设置为ON吗? [重复]

这个问题在这里已有答案: 为什么SET XACT_ABORT不是默认行为? 1个答案 我理解SET XACT_ABORT命令的目的: 当SET XACT_ABORT为ON时,如果Transact-SQL语句引发运行时错误,则终止并回滚整个事务。