处理服务器到服务器的远程存储过程中的错误

从本地 SQL Server 实例向客户端运行远程存储过程和批处理时,可能会遇到语句和批处理中止错误:

  • 发生语句中止错误时,引起该错误的语句将被终止,但远程存储过程或批处理仍会继续执行。

  • 发生批处理中止错误时,整个远程存储过程或批处理的执行将被终止。

  • 在 TRY 块的作用域内执行远程存储过程和批处理时,可以使用 TRY…CATCH 构造来处理批处理中止错误。

由语句和批处理中止错误引起的远程存储过程和批处理行为取决于本地服务器的 SET XACT_ABORT 设置。

SET XACT_ABORT 设置为 OFF

如果在本地服务器中将 SET XACT_ABORT 设置为 OFF,则远程存储过程中的任何语句中止错误都会被本地服务器作为语句中止错误传播到客户端。只有引起错误的语句才会被终止。客户端将检索对应于语句中止错误的错误消息。此外,如果远程存储过程仍然运行至完成,则 @@ERROR 将返回 0。如果错误发生在 TRY 块的作用域内,则执行将继续而不调用 CATCH 块。

远程存储过程中的任何批处理中止错误都会被本地服务器传播到客户端。调用远程存储过程的 EXECUTE 语句将被终止,但包含该 EXECUTE 语句的批处理或存储过程将继续运行。因此,@@ERROR 将返回与终止远程存储过程的错误相对应的错误代码,并且该存储过程的返回值为 NULL。如果生成错误的远程存储过程在本地服务器上的 TRY 块作用域内执行,该错误将导致控制权以及远程服务器上一次错误的相关信息传递给 CATCH 块。

在处理错误时,请在 TRY…CATCH 构造的 TRY 块的作用域内执行一个远程存储过程。如果远程存储过程未成功完成,则执行会根据远程服务器上有关最后一个错误的信息跳转到本地服务器上的关联 CATCH 块。如果远程存储过程成功完成,则执行将在本地服务器上的 TRY 块的作用域内继续,可以使用该远程存储过程的返回值。

或者,当在 TRY 块的作用域之外执行远程存储过程时,请在远程存储过程的末尾检查 @@ERROR 以确定远程过程是否已完成。如果 @@ERROR 为 0,则说明远程存储过程已成功执行,可以使用该存储过程的返回值。如果 @@ERROR 不为零,则说明远程存储过程未成功完成,无法使用该存储过程的返回值。

SET XACT_ABORT 设置为 ON

如果在本地服务器中将 SET XACT_ABORT 设置为 ON,则此设置将被传播到链接服务器。远程存储过程中的所有语句和批处理中止错误都将在本地服务器中转换为批处理中止错误。因此,调用远程存储过程的批处理或存储过程的执行以及远程存储过程都将被终止。如果生成错误的远程存储过程在本地服务器上的 TRY 块作用域内执行,该错误将导致控制权以及远程服务器上一次错误的相关信息传递给 CATCH 块。

在 TRY 块的作用域之外执行远程存储过程时,由于没有执行 EXECUTE 语句后的语句,因此无法检查 @@ERROR 的值,从而无法确定是否发生了批处理错误。因此,应在 TRY…CATCH 构造的 TRY 块的作用域内执行一个远程存储过程。如果远程存储过程未成功完成,则执行会根据远程服务器上有关最后一个错误的信息跳转到本地服务器上的关联 CATCH 块。如果远程存储过程成功完成,则执行将在本地服务器上的 TRY 块的作用域内继续,可以使用该远程存储过程的返回值。

RAISERROR 和 TRY…CATCH

在远程存储过程内调用严重性低于 20 的 RAISERROR 会引起远程服务器上的语句中止错误。本地服务器上的 TRY…CATCH 构造仅用于处理远程批处理中止错误。如果远程存储过程调用严重性低于 20 的 RAISERROR,且该远程存储过程在本地服务器上的 TRY 块的作用域内执行,则 RAISERROR 不会导致执行传递到 TRY…CATCH 构造的 CATCH 块。但是,如果远程服务器上的 RAISERROR 严重性等于或大于 20,将导致断开连接,并且本地服务器上的执行将被传递到 CATCH 块。