TRY...CATCH (Transact-SQL)
Область применения: SQL Server База данных SQL Azure Управляемый экземпляр SQL Azure конечной точке аналитики платформы Аналитики Azure Synapse Analytics (PDW) в Microsoft Fabric Хранилище в Microsoft Fabric
Реализует обработку ошибок для Transact-SQL, аналогичную обработке исключений на языках C# и Visual C++. Группа инструкций Transact-SQL может быть заключена в TRY
блок. Если в блоке TRY
возникает ошибка, элемент управления обычно передается в другую группу операторов, заключенную CATCH
в блок.
Соглашения о синтаксисе Transact-SQL
Синтаксис
BEGIN TRY
{ sql_statement | statement_block }
END TRY
BEGIN CATCH
[ { sql_statement | statement_block } ]
END CATCH
[ ; ]
Аргументы
sql_statement
Любая инструкция Transact-SQL.
statement_block
Любая группа инструкций Transact-SQL в пакете или заключена BEGIN...END
в блок.
Замечания
Конструкция TRY...CATCH
перехватывает все ошибки выполнения, имеющие серьезность выше 10, которые не закрывают подключение к базе данных.
За TRY
блоком необходимо сразу же следовать связанному CATCH
блоку. Включение любых других инструкций END TRY
между операторами и BEGIN CATCH
создает синтаксическую ошибку.
Конструкция TRY...CATCH
не может охватывать несколько пакетов. Конструкция TRY...CATCH
не может охватывать несколько блоков инструкций Transact-SQL. Например, TRY...CATCH
конструкция не может охватывать два BEGIN...END
блока инструкций Transact-SQL и не может охватывать конструкцию IF...ELSE
.
Если в коде отсутствуют ошибки, заключенные в TRY
блок, когда последняя инструкция в TRY
блоке завершается, элемент управления передается в инструкцию сразу после связанной END CATCH
инструкции.
Если в коде, заключенном в TRY
блок, возникает ошибка, элемент управления передается первой инструкции в связанном CATCH
блоке. После завершения кода в блоке CATCH
элемент управления передается оператору сразу после выполнения инструкции END CATCH
.
Примечание.
END CATCH
Если инструкция является последней инструкцией в хранимой процедуре или триггере, элемент управления передается обратно в инструкцию, которая вызывает хранимую процедуру или запускает триггер.
Ошибки, захваченные блоком CATCH
, не возвращаются в вызывающее приложение. Если любая часть сведений об ошибке должна быть возвращена приложению, код в CATCH
блоке должен сделать это с помощью таких механизмов, как SELECT
результирующие наборы или RAISERROR
PRINT
операторы.
TRY...CATCH
Конструкции могут быть вложены. Блок TRY
или CATCH
блок могут содержать вложенные TRY...CATCH
конструкции. Например, CATCH
блок может содержать внедренную TRY...CATCH
конструкцию для обработки ошибок, возникающих в коде CATCH
.
Ошибки, возникающие в блоке CATCH
, обрабатываются как ошибки, созданные в любом другом месте. CATCH
Если блок содержит вложенную конструкцию, любая ошибка в вложенном TRY
TRY...CATCH
блоке передает элемент управления в вложенный 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
блокной или для выхода из нее TRY
или CATCH
блока.
Конструкция 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
. Транзакция не может выполнять инструкции Transact-SQL, которые создают операцию записи или операцию COMMIT TRANSACTION
записи. Функция XACT_STATE
возвращает значение, -1
если транзакция была классифицирована как неуправляемая транзакция. Когда пакет завершится, ядро СУБД откатывает все активные неуправляемые транзакции. Если сообщение об ошибке не было отправлено, когда транзакция вошла в неуправляемое состояние, когда пакет завершится, сообщение об ошибке отправляется клиентскому приложению. Это указывает на то, что была обнаружена нефиксируемая транзакция и выполнен ее откат.
Дополнительные сведения о неуправляемых транзакциях и XACT_STATE
функции см . в XACT_STATE.
Примеры
А. Использование 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
Связанный контент
- 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)
- НАЧИНАТЬ... END (Transact-SQL)
- XACT_STATE (Transact-SQL)
- SET XACT_ABORT (Transact-SQL)