我创建了一个存储过程,该过程运行许多命令来修改数据。如果一切成功,我只想提交事务。我通过以下方式使用try- catch块来实现此目的(其中,真实的CATCH块使用RAISERROR返回错误消息):
BEGIN TRY BEGIN TRANSACTION UPDATE Table1 SET MyVarcharColumn = 'test' UPDATE Table2 SET MyBitColumn = 1 UPDATE Table3 SET MyIntColumn = 42 COMMIT TRANSACTION END TRY CATCH ROLLBACK TRANSACTION END CATCH
这就是我想要的方式。例如,如果我将MyBitColumn设置为’b’而不是1,则捕获了错误,控制权流到了CATCH,并且未提交事务。
我注意到的一个问题是,如果说数据库中不存在Table3,则它会出错(无效的对象名),但是CATCH块将永远不会执行,并且事务保持打开状态。
我想处理此问题,以解决数据库被修改的任何(远程)可能性(或在适当添加此存储过程的情况下发生的事情,但其中一个表没有发生)。
我应该如何处理这些错误情况?
-谢谢你的帮助。
在脚本的开头使用SET XACT_ABORT
SET XACT_ABORT ON
当SET XACT_ABORT为ON时,如果Transact-SQL语句引发运行时错误,则整个事务将终止并回滚。
我认为这是不可能的:
当以下几种类型的错误与TRY-ATCH构造在相同的执行级别上发生时,CATCH块将不对其进行处理: 编译错误(例如语法错误)会阻止批处理运行。 在语句级重新编译期间发生的错误, 例如由于延迟的名称解析而在编译后发生的对象名称解析错误。
当以下几种类型的错误与TRY-ATCH构造在相同的执行级别上发生时,CATCH块将不对其进行处理:
编译错误(例如语法错误)会阻止批处理运行。
在语句级重新编译期间发生的错误, 例如由于延迟的名称解析而在编译后发生的对象名称解析错误。
参考。
下面的示例说明了由SELECT语句生成的对象名称解析错误是不是由TRY’ATCH构造捕获的,而由CATCH块捕获的,当在存储过程中执行相同的SELECT语句时,则如何捕获该错误。
USE AdventureWorks2012; GO 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-ATCH构造传递到下一个更高级别。