设为首页
加入收藏
首 页 | 产业资讯 | 软件资讯 | 硬件资讯 | 方案应用 | DIY 硬件 | 数码伴侣 | IT 评测 | 数据调研 | 下载中心 | 在线商城 | 在线论坛
类别
今日焦点 最新方案
应用技巧
最新推荐
首页 >> 方案应用 >> 应用技巧
SQL Server 2005的XML支持与异常处理
时间:2007-8-6 20:02:55,点击:0

  问:我刚刚将 SQL Server 2000 数据库迁移到 SQL Server 2005。我听说 SQL Server 2005 在 T-SQL 中引入了 TRY/CATCH 异常处理。与现有的 IF @@ERROR <> 0 技术相比,新的异常处理如何工作呢?

  答:通常对使用 T-SQL 编写代码的抱怨是,T-SQL 始终缺少一个健壮的异常处理结构。通过 SQL Server 2000,您可以编写 T-SQL 批处理代码,以检查是否存在错误甚至何时引发错误(如果需要)。但与 TRY/CATCH 技术相比,执行此操作的技术是最基本的。首先,我将使用 @@ERROR 函数定义与异常处理相关联的问题,然后展示新的 TRY/CATCH 技术与之相比是如何执行的。

  SQL Server 公开内置的 @@ERROR 函数,该函数返回所执行的上一条 T-SQL 命令的错误号。该函数的问题在于,它始终返回从刚刚执行的上一个语句返回的错误。这意味着,如果您执行一个导致错误的 INSERT 语句,然后执行另一个不会导致错误的任意 SQL 语句,之后再查看 @@ERROR 的返回值,则该函数将返回 0,原因是上一个语句没有返回错误。您必须十分小心,以确保在执行每个单独语句之后检查 @@ERROR 的值。

  BEGIN TRANSACTION DELETE [Order Details] WHERE OrderID IN (SELECT OrderID FROM Orders WHERE CustomerID = 'ALFKI') IF @@ERROR <> 0 BEGIN ROLLBACK TRANSACTION RETURN END DELETE Orders WHERE CustomerID = 'ALFKI' IF @@ERROR <> 0 BEGIN ROLLBACK TRANSACTION RETURN END DELETE Customers WHERE CustomerID = 'ALFKI' IF @@ERROR <> 0 BEGIN ROLLBACK TRANSACTION RETURN END PRINT 'I got here' -- Normally do a COMMIT TRANSACTION here. -- But I do a ROLLBACK so I don't truly delete my test data. ROLLBACK TRANSACTION

  展示一些示例代码,这些代码将在事务内部运行,依次删除客户的定单详情、定单以及客户本身。在每个 DELETE 语句之后,代码都会检查 @@ERROR 函数的值,以查看 DELETE 语句是否导致了错误。如果是,则回滚事务,停止执行代码,然后从批处理操作返回。

  这是标准的事务管理,即如果发生错误,则中止事务,然后将数据的状态返回至其初始状态。请注意,如果一切顺利并且没有发生错误,我会打印一个成功消息,然后回滚事务。通常,我不会成功地进行回滚,因为这是一个测试事务,我实际上并不希望删除我的数据。

  请注意,我必须遵循带有 @@ERROR 函数的每个语句,然后再使用 ROLLBACK 和 RETURN。该方法十分糟糕。假设编写一个包含许多查询(这些查询都需要检查)的事务。该过程可以通过 GOTO 语句来稍加简化,当然我并不是 GOTO 语句的提倡者,因为它们依旧未解决需要在查询操作之后立即检查 @@ERROR 函数的问题。

  SQL Server 2005 仍然支持 @@ERROR 函数,但它还包括了广为人知的 TRY/CATCH 模式。TRY/CATCH 结构与 C# try/catch 结构的类似之处在于,在 try 块中捕获错误,然后转移到 catch 块执行。(T-SQL 版本的 TRY/CATCH 没有 FINALLY 子句选项,但 C# 版本有。您可以通过捕获异常、不执行返回、然后使用适当的清除代码执行 catch 块来进行模拟。)因此,在某些情况下需要注意这一点,例如,在指定了 CURSOR 并在 T-SQL TRY 块中引发错误时打开该游标的情况。在这种情况下,应该在 CATCH 块中检查游标以查看它是否已打开;如果已打开,则应将其关闭并取消指定。

  BEGIN TRY BEGIN TRANSACTION DELETE [Order Details] WHERE OrderID IN (SELECT OrderID FROM Orders WHERE CustomerID = 'ALFKI') DELETE Orders WHERE CustomerID = 'ALFKI' DELETE Customers WHERE CustomerID = 'ALFKI' PRINT 'committing deletes' COMMIT TRANSACTION END TRY BEGIN CATCH ROLLBACK TRANSACTION RETURN END CATCH

  看到上面代码中的 TRY/CATCH 结构后,您可能会震惊于它与 @@ERROR 技术相比是多么简洁。请注意,对于 TRY/CATCH 块,不需要重复检查是否有错误,因而减少了代码行数同时也减少了出现编码错误的地方。

  上面代码中的代码试图开始一个事务,执行一系列 DELETE 语句,然后提交该事务。(另请注意,在我的示例中,我没有提交事务而是回滚该事务,因此实际上并没有删除数据。实际上,这应该是一个 COMMIT TRAN 语句。)

  可以在 TRY/CATCH 结构中访问多个内置函数,以帮助您确定导致代码进入 CATCH 块的原因。例如,可以在 CATCH 块内部添加以下语句,返回有关该错误的信息:

  SELECT ERROR_LINE() AS ErrorLine, ERROR_MESSAGE() AS ErrorMessage, ERROR_NUMBER() AS ErrorNumber, ERROR_PROCEDURE() AS ErrorProcedure, ERROR_SEVERITY() AS ErrorSeverity, ERROR_STATE() AS ErrorState

  这些函数(如果适用)将返回发生错误的行号、错误消息、错误号、存储过程或发生错误的触发器、错误的严重级别以及错误的状态级别。

  TRY/CATCH 结构捕获严重度为 11 到 19(包括 11 和 19)的错误。低于 11 的严重级别是警告,不视为错误。严重级别为 20 及以上的错误视为严重错误。然而,如果这些严重级别为 20 及以上的错误没有导致数据库引擎停止,则它们将由 TRY/CATCH 捕获。总之,TRY/CATCH 语句更易于读取、更易于维护,且更不容易导致复制和粘贴错误。此外,@@ERROR 技术也不总是很可靠。例如,某些错误会中止计划或整个批处理。

第1页 第2页 第3页
打印】【关闭
版权所有:成都A数码信息技术有限公司 执行时间:62.500毫秒
网站留言 | 关于我们 | 联系我们