Try-Catch在存储过程中的奇怪行为

时间:2014-10-17 23:59:15

标签: sql-server tsql stored-procedures transactions try-catch

我有一个存储过程,我需要转换为类型,但不知道转换是否会成功。在命令式语言中,我会使用某种TryCast模式。我认为这在T-SQL中是等效的:

begin try
   select cast(@someValue as SomeType)
end try begin catch end catch

从表面上看,它似乎是等效的。如果@SomeTypeVar未初始化且投射失败,我会NULL使用;如果演员成功,则为正确的值。

我在存储过程中使用了相同的代码,但是产生了一个错误:Msg 2812, Level 16, State 62, Line 20. The current transaction cannot be committed and cannot support operations that write to the log file. Roll back the transaction.一些研究引发了我关于Stack Overflow和T-SQL中try-catch失败的时间表的其他问题:

  

TRY ... CATCH构造不会捕获以下条件:

     
      
  • 严重性为10或10的警告或信息性消息   降低。
  •   
  • 严重性为20或更高的错误,用于停止SQL   会话的服务器数据库引擎任务处理。如果有错误   发生严重性为20或更高的数据库连接   没有被打乱,TRY ...... CATCH将处理错误。
  •   
  • 注意事项,如   客户端中断请求或破坏的客户端连接。
  •   
  • 当   会话由系统管理员使用KILL结束   声明。
  •   
     

CATCH不处理以下类型的错误   阻止它们发生在与TRY ... CATCH相同的执行级别   构建体:

     
      
  • 编译阻止批处理的错误,例如语法错误   运行。
  •   
  • 语句级重新编译期间发生的错误,例如   作为编译后发生的对象名称解析错误,因为   延迟名称解析。
  •   
     

这些错误将返回到该级别   运行批处理,存储过程或触发器。

起初,我以为我陷入了语句级重新编译桶(因为我的错误级别是16),直到我试图将问题一分为二。最小的再现如下:

create procedure failsInTransactions
as
begin
    begin try
      select cast(@someValue as SomeType)
    end try begin catch end catch
end

和调用代码:

begin tran
  exec failsInTransactions
commit

这产生了我上面讨论的错误。但是,我记得如果存储过程没有任何参数,你可以在没有exec的情况下调用它。这样:

begin tran
  failsInTransactions
commit

成功Command(s) completed successfully.进一步的实验导致我再次出现16级错误:

begin try
  select 1/0
end try begin catch end catch

在两种情况下都有效,不产生任何输出行。

我有两个问题:

  1. 为什么在使用和不使用exec时调用该过程有不同的行为?
  2. 为什么在catch之后会出现同一错误级别的其他错误?

1 个答案:

答案 0 :(得分:3)

只有当EXECUTE关键字是批处理中的第一个语句时,它才是可选的。它与参数无关,在所有其他上下文中都是必需的。 Microsoft从Sybase代码库以及其他许多松散的T-SQL解析规则继承了这种奇怪的行为。我建议你遵循严格的T-SQL编码风格来避免陷阱。

下面的代码运行时没有错误,因为它根本没有执行proc。由于没有分号语句终止符,因此存储过程名称将成为BEGIN TRAN语句的一部分,并被解释为事务名称。

begin tran
  failsInTransactions
commit

如果添加语句终止符,您将在编译期间获得预期的语法错误,这将引导您沿着路径指定EXEC。

begin tran;
  EXEC failsInTransactions;
commit;

请注意,不推荐使用语句终结符,因此我建议您养成指定它们的习惯。请参阅https://www.dbdelta.com/always-use-semicolon-statement-terminators/