T-SQL中try..catch调用遗留存储过程无法捕获返回错误如何处理
问题
我在try..catch语句块中调用一个遗留存储过程,当该存储过程向用户返回包含简易错误详情的消息时,我的try..catch无法捕获到这条消息。
该遗留存储过程返回的消息示例如下:
错误状态:1,错误严重级别:16,错误编号:50000,错误行号:33,错误存储过程:LegacyStoredProcedure
错误信息:请处理…… 正在回滚事务。
请问是否有方法可以捕获到该存储过程返回的上述错误消息?我当前使用的代码如下:
BEGIN TRY BEGIN Transaction ..... EXEC *thelegacySP* ..... COMMIT Transaction END TRY BEGIN CATCH DECLARE @ErrorLine int, @ErrorMessage nvarchar(2048), @ErrorNumber int, @ErrorProcedure nvarchar(126), @ErrorSeverity int, @ErrorState int; SELECT @ErrorLine = ERROR_LINE(), @ErrorMessage = ERROR_MESSAGE(), @ErrorNumber = ERROR_NUMBER(), @ErrorProcedure = '*MyNewSP*', @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE(), @now = GETDATE() RAISERROR(@ErrorMessage, @ErrorSeverity, @ErrorState) IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION INSERT INTO Validation.Table VALUES( @ErrorProcedure ,@ErrorNumber ,@ErrorMessage ,@ErrorSeverity ,@ErrorState ,@ErrorLine ,@now ) END CATCH
解决方案
常见原因
无法捕获错误的问题通常由两类原因导致:
- 遗留存储过程内部使用
PRINT语句输出错误信息,而非通过正式的错误抛出语句输出,这类普通消息不会触发外层TRY/CATCH的捕获逻辑 - 遗留存储过程内部已经封装了
TRY/CATCH逻辑,捕获错误后仅做了回滚事务、打印消息的处理,没有主动重新抛出错误,导致外层感知不到错误发生
修复步骤
1. 调整遗留存储过程的错误抛出逻辑(优先)
如果有权限修改遗留存储过程,将错误输出逻辑调整为使用THROW语句(SQL Server 2012及以上版本支持)或者RAISERROR语句(要求错误严重级别≥11),即可被外层的TRY/CATCH捕获。如果没有权限修改遗留存储过程,直接走下一步。
2. 外层调用逻辑增加事务异常配置
在开启事务前添加SET XACT_ABORT ON配置,该参数会强制在发生执行错误时终止批处理、回滚事务并抛出错误,避免部分低优先级错误被静默忽略,调整后的外层代码参考如下:
BEGIN TRY -- 新增配置,强制错误抛出 SET XACT_ABORT ON BEGIN Transaction ..... EXEC *thelegacySP* ..... COMMIT Transaction END TRY BEGIN CATCH DECLARE @ErrorLine int, @ErrorMessage nvarchar(2048), @ErrorNumber int, @ErrorProcedure nvarchar(126), @ErrorSeverity int, @ErrorState int, -- 补全原有代码中缺失的@now变量声明 @now DATETIME; SELECT @ErrorLine = ERROR_LINE(), @ErrorMessage = ERROR_MESSAGE(), @ErrorNumber = ERROR_NUMBER(), @ErrorProcedure = '*MyNewSP*', @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE(), @now = GETDATE() -- 先回滚事务再抛出错误/写入日志 IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION INSERT INTO Validation.Table VALUES( @ErrorProcedure ,@ErrorNumber ,@ErrorMessage ,@ErrorSeverity ,@ErrorState ,@ErrorLine ,@now ) -- 替换原有RAISERROR为THROW,无需手动传递错误参数,会完整保留原始错误属性 THROW; END CATCH
额外说明
如果你使用的SQL Server版本不支持THROW语句,可以保留原有RAISERROR逻辑,但要注意调整执行顺序,先回滚事务再抛出错误,避免事务未回滚时抛出错误导致后续的日志写入逻辑执行失败。
内容的提问来源于stack exchange,提问作者Tarek Latif
相关产品推荐
相关产品推荐

