适用于:SQL Server
Azure SQL 数据库
Azure SQL 托管实例
Azure Synapse Analytics
分析平台系统(PDW)
Microsoft Fabric 中的 SQL 分析终结点
Microsoft Fabric 中的仓库
Microsoft Fabric 预览版中的 SQL 数据库
为 Transact-SQL 实现与 C# 和 Visual C++ 语言中的异常处理类似的错误处理。 一组 Transact-SQL 语句可以包含在块 TRY 中。 如果块中 TRY 发生错误,控件通常传递给包含在块中的另一 CATCH 组语句。
Syntax
BEGIN TRY
{ sql_statement | statement_block }
END TRY
BEGIN CATCH
[ { sql_statement | statement_block } ]
END CATCH
[ ; ]
Arguments
sql_statement
任何 Transact-SQL 语句。
statement_block
批处理中的任何一组 Transact-SQL 语句或包含在块 BEGIN...END 中。
Remarks
TRY...CATCH构造捕获严重性高于 10 的所有执行错误,这些错误不会关闭数据库连接。
块 TRY 必须紧跟关联 CATCH 块。 包括语句END TRY之间的BEGIN CATCH任何其他语句将生成语法错误。
构造 TRY...CATCH 不能跨越多个批处理。 构造 TRY...CATCH 不能跨越 Transact-SQL 语句的多个块。 例如,构造不能跨越 Transact-SQL 语句的两TRY...CATCH个BEGIN...END块,并且不能跨越构造IF...ELSE。
如果代码中没有包含在块中的错误,则当块中的TRY最后一个TRY语句完成时,控件会在关联END CATCH语句之后立即传递给该语句。
如果代码中有一个包含在块中的 TRY 错误,则控件将传递给关联 CATCH 块中的第一个语句。 当块中的 CATCH 代码完成时,控件会紧接在语句之后 END CATCH 传递给该语句。
Note
END CATCH如果该语句是存储过程或触发器中的最后一个语句,则控制权将传回调用存储过程或触发触发器的语句。
被块捕获 CATCH 的错误不会返回到调用应用程序。 如果错误信息的任何部分必须返回到应用程序,则块中的CATCH代码必须通过使用结果集或SELECT语句RAISERROR等PRINT机制执行此操作。
TRY...CATCH 构造可以嵌套。
TRY块或CATCH块可以包含嵌套TRY...CATCH构造。 例如,块 CATCH 可以包含嵌入 TRY...CATCH 构造来处理代码遇到的 CATCH 错误。
块中 CATCH 遇到的错误将被视为在其他任何位置生成的错误。
CATCH如果块包含嵌套TRY...CATCH构造,则TRY嵌套块中的任何错误都会将控制传递给嵌套CATCH块。 如果没有嵌套 TRY...CATCH 构造,错误将传回调用方。
TRY...CATCH 构造从存储过程或块中的 TRY 代码执行的触发器中捕获未经处理的错误。 或者,存储过程或触发器可以包含自己的 TRY...CATCH 构造来处理其代码生成的错误。 例如,当块执行存储过程和存储过程中发生错误时 TRY ,可以通过以下方式处理该错误:
如果存储过程不包含其自己的
TRY...CATCH构造,则错误会将控件CATCH返回到与TRY包含语句的EXECUTE块关联的块。如果存储过程包含构造
TRY...CATCH,则错误会将控件传输到CATCH存储过程中的块。CATCH块代码完成后,控件将紧接在调用存储过程的语句之后EXECUTE传回该语句。
GOTO 语句不能用于输入 TRY 或 CATCH 块。
GOTO语句可用于跳转到相同TRY或CATCH块内的标签或离开或TRYCATCH块。
TRY...CATCH构造不能用于用户定义的函数。
检索错误信息
在块的作用域 CATCH 中,可以使用以下系统函数获取导致 CATCH 执行块的错误的相关信息:
| Function | Description |
|---|---|
| ERROR_NUMBER | 返回错误的数目。 |
| ERROR_SEVERITY | 返回严重性。 |
| ERROR_STATE | 返回错误状态号。 |
| ERROR_PROCEDURE | 返回发生错误的存储过程或触发器的名称。 |
| ERROR_LINE | 返回导致错误的例程中的行号。 |
| ERROR_MESSAGE | 返回错误消息的完整文本。 该文本包括为所有可替换参数提供的值,如长度、对象名或时间。 |
如果这些函数在块范围NULL之外调用,则返回CATCH这些函数。 可以使用这些函数从块范围内 CATCH 的任何位置检索错误信息。 例如,下面的脚本显示了包含错误处理函数的存储过程。 在 CATCH 构造的 TRY...CATCH 块中,调用了该存储过程并返回有关错误的信息。
-- Verify that the stored procedure does not already exist.
IF OBJECT_ID('usp_GetErrorInfo', 'P') IS NOT NULL
DROP PROCEDURE usp_GetErrorInfo;
GO
-- Create procedure to retrieve error information.
CREATE PROCEDURE usp_GetErrorInfo
AS
SELECT ERROR_NUMBER() AS ErrorNumber,
ERROR_SEVERITY() AS ErrorSeverity,
ERROR_STATE() AS ErrorState,
ERROR_PROCEDURE() AS ErrorProcedure,
ERROR_LINE() AS ErrorLine,
ERROR_MESSAGE() AS ErrorMessage;
GO
BEGIN TRY
-- Generate divide-by-zero error.
SELECT 1 / 0;
END TRY
BEGIN CATCH
-- Execute error retrieval routine.
EXECUTE usp_GetErrorInfo;
END CATCH;
这些ERROR_*函数还可以在CATCH本机编译的存储过程内的块中工作。
TRY 不受影响的错误...CATCH 构造
TRY...CATCH 构造不会捕获以下条件:
严重级别为 10 或更低的警告或信息性消息。
严重级别为 20 或更高且终止会话的 SQL Server 数据库引擎任务处理的错误。 如果发生严重性为 20 或更高的错误,并且数据库连接不会中断,
TRY...CATCH请处理该错误。需要关注的消息,如客户端中断请求或客户端连接中断。
当系统管理员使用
KILL语句结束会话时。
在与构造相同的执行CATCH级别发生时,块不会处理TRY...CATCH以下类型的错误:
编写错误,例如禁止运行批处理的语法错误。
语句级重新编写过程中出现的错误,例如由于名称解析延迟而造成在编写后出现对象名解析错误。
对象名解析错误
这些错误会被返回到运行批处理、存储过程或触发器的级别。
如果在编译或语句级重新编译期间在较低执行级别(例如,执行 sp_executesql 或用户定义存储过程)内在块内 TRY 发生错误,则错误发生在低于构造的级别 TRY...CATCH ,将由关联的 CATCH 块处理。
以下示例演示了构造未捕获SELECT由语句生成的TRY...CATCH对象名称解析错误,但在存储过程内执行同CATCH一语句时,块会捕获SELECT该错误。
BEGIN TRY
-- Table does not exist; object name resolution
-- error not caught.
SELECT *
FROM NonexistentTable;
END TRY
BEGIN CATCH
SELECT ERROR_NUMBER() AS ErrorNumber,
ERROR_MESSAGE() AS ErrorMessage;
END CATCH
未捕获错误,并且控制将构造传出 TRY...CATCH 到下一个更高的级别。
在 SELECT 存储过程内运行该语句会导致错误发生在低于 TRY 块的级别。 该错误由 TRY...CATCH 构造处理。
-- Verify that the stored procedure does not exist.
IF OBJECT_ID(N'usp_ExampleProc', N'P') IS NOT NULL
DROP PROCEDURE usp_ExampleProc;
GO
-- Create a stored procedure that will cause an
-- object resolution error.
CREATE PROCEDURE usp_ExampleProc
AS
SELECT *
FROM NonexistentTable;
GO
BEGIN TRY
EXECUTE usp_ExampleProc;
END TRY
BEGIN CATCH
SELECT ERROR_NUMBER() AS ErrorNumber,
ERROR_MESSAGE() AS ErrorMessage;
END CATCH;
不可提交事务和XACT_STATE
如果在块中 TRY 生成的错误导致当前事务的状态失效,则事务被归类为不可提交事务。 通常在块外部 TRY 结束事务的错误会导致事务在块内 TRY 发生错误时进入不可提交状态。 不可提交的事务只能执行读取操作或 ROLLBACK TRANSACTION。 事务无法执行生成写入操作或 a COMMIT TRANSACTION. 如果事务已分类为不可提交事务,该 XACT_STATE 函数将返回一个值 -1 。 当批处理结束时,数据库引擎将回滚所有不可提交的活动事务。 如果事务进入不可提交状态时未发送错误消息,则批处理完成后,会将错误消息发送到客户端应用程序。 该消息指示检测到并回滚了一个不可提交的事务。
有关不可提交事务和 XACT_STATE 函数的详细信息,请参阅 XACT_STATE。
Examples
A. Use TRY...CATCH
下面的示例显示生成被零除错误的 SELECT 语句。 该错误会使执行跳转到关联的 CATCH 块。
BEGIN TRY
-- Generate a divide-by-zero error.
SELECT 1 / 0;
END TRY
BEGIN CATCH
SELECT ERROR_NUMBER() AS ErrorNumber,
ERROR_SEVERITY() AS ErrorSeverity,
ERROR_STATE() AS ErrorState,
ERROR_PROCEDURE() AS ErrorProcedure,
ERROR_LINE() AS ErrorLine,
ERROR_MESSAGE() AS ErrorMessage;
END CATCH;
GO
B. 使用 TRY...事务中的 CATCH
以下示例显示 TRY...CATCH 块在事务内的工作方式。
TRY 块内的语句会生成违反约束的错误。
BEGIN TRANSACTION;
BEGIN TRY
-- Generate a constraint violation error.
DELETE
FROM Production.Product
WHERE ProductID = 980;
END TRY
BEGIN CATCH
SELECT ERROR_NUMBER() AS ErrorNumber,
ERROR_SEVERITY() AS ErrorSeverity,
ERROR_STATE() AS ErrorState,
ERROR_PROCEDURE() AS ErrorProcedure,
ERROR_LINE() AS ErrorLine,
ERROR_MESSAGE() AS ErrorMessage;
IF @@TRANCOUNT > 0
ROLLBACK TRANSACTION;
END CATCH;
IF @@TRANCOUNT > 0
COMMIT TRANSACTION;
GO
C. 使用 TRY...CATCH 与 XACT_STATE
以下示例显示如何使用 TRY...CATCH 构造来处理事务内发生的错误。
XACT_STATE 函数确定应提交事务还是应回滚事务。 在本示例中,SET XACT_ABORT 状态为 ON。 在发生违反约束的错误时,这会使事务处于不可提交状态。
-- Check to see whether this stored procedure exists.
IF OBJECT_ID(N'usp_GetErrorInfo', N'P') IS NOT NULL
DROP PROCEDURE usp_GetErrorInfo;
GO
-- Create procedure to retrieve error information.
CREATE PROCEDURE usp_GetErrorInfo
AS
SELECT ERROR_NUMBER() AS ErrorNumber,
ERROR_SEVERITY() AS ErrorSeverity,
ERROR_STATE() AS ErrorState,
ERROR_LINE() AS ErrorLine,
ERROR_PROCEDURE() AS ErrorProcedure,
ERROR_MESSAGE() AS ErrorMessage;
GO
-- SET XACT_ABORT ON will cause the transaction to be uncommittable
-- when the constraint violation occurs.
SET XACT_ABORT ON;
BEGIN TRY
BEGIN TRANSACTION;
-- A FOREIGN KEY constraint exists on this table. This
-- statement will generate a constraint violation error.
DELETE
FROM Production.Product
WHERE ProductID = 980;
-- If the DELETE statement succeeds, commit the transaction.
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
-- Execute error retrieval routine.
EXECUTE usp_GetErrorInfo;
-- Test XACT_STATE:
-- If 1, the transaction is committable.
-- If -1, the transaction is uncommittable and should
-- be rolled back.
-- XACT_STATE = 0 means that there is no transaction and
-- a commit or rollback operation would generate an error.
-- Test whether the transaction is uncommittable.
IF (XACT_STATE()) = -1
BEGIN
PRINT N'The transaction is in an uncommittable state. Rolling back transaction.'
ROLLBACK TRANSACTION;
END;
-- Test whether the transaction is committable.
-- You may want to commit a transaction in a catch block if you want to commit changes to statements that ran prior to the error.
IF (XACT_STATE()) = 1
BEGIN
PRINT N'The transaction is committable. Committing transaction.'
COMMIT TRANSACTION;
END;
END CATCH;
GO
Related content
- THROW (Transact-SQL)
- 数据库引擎错误严重性
- ERROR_LINE (Transact-SQL)
- ERROR_MESSAGE (Transact-SQL)
- ERROR_NUMBER (Transact-SQL)
- ERROR_PROCEDURE (Transact-SQL)
- ERROR_SEVERITY (Transact-SQL)
- ERROR_STATE (Transact-SQL)
- RAISERROR (Transact-SQL)
- @@ERROR (Transact-SQL)
- GOTO (Transact-SQL)
- BEGIN...END (Transact-SQL)
- XACT_STATE (Transact-SQL)
- SET XACT_ABORT (Transact-SQL)