您希望编写代码以便将新的雇员行插入到该表中。您还希望用一些纠正性的活动响应失败情况。按如下方式使用新的 TRY...CATCH 结构:
BEGIN TRY INSERT INTO Employees(empid, empname, mgrid) VALUES(1, 'Emp1', NULL) PRINT 'After INSERT.' END TRY BEGIN CATCH PRINT 'INSERT failed.' /* perform corrective activity */ END CATCH
当您首次运行该代码时,应当获得输出“After INSERT ”。当您第二次运行它时,应当获得输出“INSERT Failed ”。
如果 TRY 块中的代码没有任何错误地完成,则控制被传递给相应的 CATCH 块后面的第一个语句。当 TRY 块中的语句失败时,控制被传递给相应的 CATCH 块中的第一个语句。请注意,如果错误被 CATCH 块捕获,则它不会返回到调用应用程序。如果您还希望应用程序获得错误信息,则必须自己将该信息提供给应用程序(例如,使用 RAISERROR 或作为查询的结果集)。所有错误信息都借助于四个新的函数在 CATCH 块中提供给您:ERROR_NUMBER()、ERROR_MESSAGE()、ERROR_SEVERITY() 和 ERROR_STATE()。这些函数可以在 CATCH 块中您喜欢的任何位置多次查询,并且它们的值保持不变。这与除 DECLARE 以外还受到任何语句影响的 @@error
函数(因此必须在 CATCH 块的第一个语句中查询它)相反。ERROR_NUMBER() 可以用作 @@error 的替代函数,而其他三个函数则完全按照由错误生成的样子向您提供该信息的其余部分。此类信息在低于 SQL Server 2005 的 SQL Server 版本中无法获得。
如果在批处理或例程(存储过程、触发器、用户定义的函数、动态代码)中生成了未处理的错误,并且某个较高级别的代码在 TRY 块内部调用了该批处理或例程,则控制被传递给该较高级别的相应 CATCH 块。如果该较高级别没有在 TRY 块内调用该内部级别,则 SQL Server 将继续在调用堆栈中的较高级别中查找 TRY 块,并且会将控制传递给找到的第一个 TRY...CATCH 结构的 CATCH 块。如果未找到,则将错误返回给调用应用程序。
作为一个更详细的示例,以下代码根据导致失败的错误的类型做出不同的反应,并且输出消息以表明代码的哪些部分已经被激活:
PRINT 'Before TRY...CATCH block.' BEGIN TRY PRINT ' Entering TRY block.' INSERT INTO Employees(empid, empname, mgrid) VALUES(2, 'Emp2', 1) PRINT ' After INSERT.' PRINT ' Exiting TRY block.' END TRY BEGIN CATCH PRINT ' Entering CATCH block.' IF ERROR_NUMBER() = 2627 BEGIN PRINT ' Handling PK violation...' END ELSE IF ERROR_NUMBER() = 547 BEGIN PRINT ' Handling CHECK/FK constraint violation...' END ELSE IF ERROR_NUMBER() = 515 BEGIN PRINT ' Handling NULL violation...' END ELSE IF ERROR_NUMBER() = 245 BEGIN PRINT ' Handling conversion error...' END ELSE BEGIN PRINT ' Handling unknown error...' END PRINT ' Error Number: ' + CAST(ERROR_NUMBER() AS VARCHAR(10)) PRINT ' Error Message: ' + ERROR_MESSAGE() PRINT ' Error Severity: ' + CAST(ERROR_SEVERITY() AS VARCHAR(10)) PRINT ' Error State : ' + CAST(ERROR_STATE() AS VARCHAR(10)) PRINT ' Exiting CATCH block.' END CATCH PRINT 'After TRY...CATCH block.'
请注意,ERROR_NUMBER() 函数在 CATCH 块中被多次调用,并且它总是返回导致控制传递给该 CATCH 块的错误的编号。该代码将雇员 2 作为先前插入的雇员 1 的下属插入,并且在首次运行时应当没有任何错误地完成,并生成以下输出:
Before TRY...CATCH block. Entering TRY block. After INSERT. Exiting TRY block. After TRY...CATCH block.
请注意,CATCH 块被跳过。第二次运行该代码时,应当生成以下输出:
Before TRY...CATCH block. Entering TRY block. Entering CATCH block. Handling PK violation... Error Number: 2627 Error Message: Violation of PRIMARY KEY constraint 'PK_Employees'. Cannot insert duplicate key in object 'Employees'. Error Severity: 14 Error State : 1 Exiting CATCH block. After TRY...CATCH block.
请注意,TRY 块被进入,但未完成。作为主键冲突错误的结果,控制被传递给 CATCH 块,该块会识别并处理该错误。类似地,如果您分配的值不是有效的雇员 ID 数据,例如,0(它违反了 CHECK 约束)、NULL(它不允许在 employeeid 中使用)以及 'a ,' (它无法转换为 INT ),则您会得到相应的错误,并且会激活相应的处理代码。
如果您要在 TRY 块中使用显式事务,则您可能希望在 CATCH 块中的错误处理代码中调查事务状态,以确定操作过程。SQL Server 2005 提供了新的函数 XACT_STATE() 以返回事务状态。该函数可能返回的值为:0、-1 和 1。0 返回值意味着没有打开任何事务。试图提交或回滚该事务时,会生成错误。1 返回值意味着事务已打开,并且可以提交或回滚。您需要根据自己的需要和错误处理逻辑确定是提交还是回滚该事务。-1 返回值意味着事务已打开但处于无法提交的状态 — 这是 SQL Server 2005 中引入的新的事务状态。当生成可能会导致事务被中止的错误(通常,严重度为 17 或更高)时,TRY 块内的事务会进入无法提交的状态。无法提交的事务会保持所有打开的锁,并且只允许您读取数据。您不能提交任何需要写事务日志的活动,这意味着当事务处于无法提交的状态时,您无法更改数据。为了终止该事务,您必须发出回滚。您不能提交该事务,而只能在可以接受任何修改之前将其回滚。以下示例演示了如何使用 XACT_STATE() 函数:
BEGIN TRY BEGIN TRAN INSERT INTO Employees(empid, empname, mgrid) VALUES(3, 'Emp3', 1) /* other activity */ COMMIT TRAN PRINT 'Code completed successfully.' END TRY BEGIN CATCH PRINT 'Error: ' + CAST(ERROR_NUMBER() AS VARCHAR(10)) + ' found.' IF (XACT_STATE()) = -1 BEGIN PRINT 'Transaction is open but uncommittable.' /* ...investigate data... */ ROLLBACK TRANSACTION -- can only ROLLBACK /* ...handle the error... */ END ELSE IF (XACT_STATE()) = 1 BEGIN PRINT 'Transaction is open and committable.' /* ...handle error... */ COMMIT TRANSACTION -- or ROLLBACK END ELSE BEGIN PRINT 'No open transaction.' /* ...handle error... */ END END CATCH
TRY 块在显式事务内部提交代码。它插入一个新的雇员行,并且在同一事务内部执行其他一些活动。CATCH 块输出错误编号,并且调查事务状态以确定操作过程。如果事务已打开并且无法提交,则 CATCH 块会调查数据,回滚该事务,然后采取任何需要数据修改的纠正性措施。如果该事务已打开并且可以提交,则 CATCH 块会处理错误并提交(也可能回滚)。如果没有任何事务打开,则错误被处理。不会发出任何提交或回滚。如果您是首次运行该代码,则会插入对应于雇员 3 的新的雇员行,并且代码成功完成,产生以下输出:
Code completed successfully.
如果您是第二次运行该代码,则会生成主键冲突错误,并且您会获得以下输出:
Error: 2627 found. Transaction is open and commi






