首页 > 解决方案 > 为什么在引发除以零异常后执行插入语句

问题描述

我有以下查询。

IF Object_id('tempdb..#test_tran') IS NOT NULL 
  DROP TABLE #test_tran 

CREATE TABLE #test_tran 
  ( 
     id   INT, 
     name VARCHAR(255) 
  ) 

GO

---------------------------------------- 

BEGIN TRAN 

  DECLARE @a FLOAT = 1 / 0.0 

  INSERT INTO #test_tran VALUES (1, 'Red') 

COMMIT TRAN 

---------------------------------------- 
GO 

SELECT * FROM   #test_tran

输出是

Msg 8134, Level 16, State 1, Line 17
Divide by zero error encountered.

(1 row affected)

(1 row affected)

Completion time: 2020-07-12T12:39:16.9097805+03:00

为什么在 DECLARE @a FLOAT = 1 / 0.0 发生错误时事务没有停止?为什么在引发除以零异常后执行插入语句?

如果我使用 BEGIN TRY BEGIN CATCH 异常被捕获并阻止插入,但我想了解为什么在抛出异常后继续执行。

标签: sql-server

解决方案


SQL 异常的行为方式与它们在应用程序代码中的行为方式不同。它们并不总是导致堆栈展开到一个 catch 块(或进程终止)——除非你实际上有一个 catch 块。

在 SQL 中,一些错误会导致整个批处理终止,而其他错误可能不会 - 取决于xact_abort. 关于这方面的一些信息可以在 的备注中找到raiserror

如果错误severity大于 10,并且错误不在块中try,则客户端应用程序将接收该错误作为异常的一部分。

如果错误severity大于 20,则整个批处理 - 以及连接 - 将终止。

因此,有三种方法可以“检测” TSQL 中的错误:

  1. 使用 try/catch
  2. @@error在每条语句之后检查系统变量的值。
  3. 如果你总是想停止处理,那么set xact_abort on

推荐阅读