DDL 语句错误从不调用 CATCH

Ton*_*raj 3 sql-server-2008 transaction ddl

在此处输入图片说明 当我尝试关闭下面的 SS Management Studio 窗口时出现错误

我知道 DDL 语句是隐式 COMMIT,下面的警告消息是因为 BEGIN TRAN 从不 COMMIT 或 ROLLBACK。更改 DDL 语句中止并且从未循环通过 CATCH 块。无法理解为什么在错误发生后控制没有传递给 CATCH 块(这在任何其他 DML 语句中都会发生)你能解释一下为什么 CATCH 中的语句从未针对此 DDL 错误执行吗?

Sol*_*zky 8

怎么没抓到?因为 TRY / CATCH 不能捕获所有类型的错误。但是您可以通过将其包装在 EXEC() 中来捕获非系统关键的内容,例如:

BEGIN TRY
   EXEC('ALTER TABLE...');
END TRY
Run Code Online (Sandbox Code Playgroud)

ALTER 中的错​​误将失败到 EXEC,然后将返回到 TRY/CATCH 块,报告一个简单的、可捕获的错误。

有关更多详细信息,TRY...CATCH的 MSDN 页面指出:

当以下类型的错误发生在与 TRY…CATCH 构造相同的执行级别时,它们不会被 CATCH 块处理:

  • 阻止批处理运行的编译错误,例如语法错误。

  • 语句级重编译过程中出现的错误,例如编译后由于名称解析延迟导致的对象名称解析错误。

关于对象名称解析错误的第二个要点是导致 ALTER 语句失败并且无法被 CATCH 块处理的原因。

编辑:
关于您关于“DDL 语句是隐式提交”的声明:我不确定您的确切含义,但所有(几乎所有)查询本身都是事务。这意味着,单查询批有没有用明确的BEGIN TRAN/ COMMIT/ ROLLBACK。如果语句失败,它会自动回滚,如果成功则它会自动提交。你只使用BEGIN TRAN/ COMMIT/ROLLBACK如果你要有条件地回滚出于某种原因结构。使用该TRY...CATCH结构来正确处理错误仍然是一个好主意,但是通过显式事务处理,您一无所获(至少使用问题中发布的代码)。发布的代码与以下代码之间绝对没有区别:

BEGIN TRY
   EXEC('ALTER TABLE...');
END TRY
BEGIN CATCH
   SELECT 'I''m in Catch';
END CATCH;
Run Code Online (Sandbox Code Playgroud)

  • @AaronBertrand :并且要_非常_清楚;),如果将其放入子进程中,甚至编译错误也可能会被捕获。自行运行:`CREATE TABLE #bob (Col1 INT);`。现在自己运行这整个事情:`BEGIN TRY SELECT 1; EXEC('SELECT b.Col2 FROM #bob b;'); 结束尝试开始捕捉选择 23;结束捕捉;`。此处批处理并未中止并进入 CATCH 块,即使 EXEC 中的 SELECT 是编译错误。 (2认同)