在存储过程中可以且应该使用特殊结构来处理错误。
在 SQL Server 中 主要的机制是 TRY...CATCH 块,其中所有在 TRY 中发生的错误都会被捕获,而在 CATCH 中可以记录详细信息。可用的函数包括 ERROR_NUMBER() 和 ERROR_MESSAGE() 来获取详细信息。
BEGIN TRY -- 高风险操作 UPDATE Accounts SET balance = balance - 100 WHERE id = 1; END TRY BEGIN CATCH INSERT INTO ErrorLog( ErrorTime, ErrorNumber, ErrorMessage, UserName ) VALUES ( GETDATE(), ERROR_NUMBER(), ERROR_MESSAGE(), SUSER_SNAME() ); -- 额外的恢复或 ROLLBACK END CATCH
在 Oracle 中 更常使用 EXCEPTION 块:
BEGIN UPDATE ...; EXCEPTION WHEN OTHERS THEN INSERT INTO error_log VALUES (..., SQLERRM); END;
需要记住的要点:
CATCH 块中的异常会导致上下文错误丢失吗?如何实现嵌套的错误处理?
回答和示例: 如果在 CATCH 块中发生错误(例如,由于 ErrorLog 表不可用),则原始错误的上下文将丢失,导致故障原因的信息可能会遗失。
为了防止这种情况,请将记录日志封装在具有自己 TRY...CATCH 的单独过程内,以确保始终捕获“错误处理程序中的错误”。
BEGIN TRY -- 主代码 END TRY BEGIN CATCH EXEC LogError @Error = ERROR_MESSAGE(); END CATCH -- LogError 过程本身包含自己的 TRY...CATCH
历史
项目:财务报告。 在存储过程中添加了 TRY...CATCH 块,但没有记录导致错误的参数。因此,在捕获关键故障时,必须手动查找备份中的情况——根本原因并不明显。
历史
项目:文档流自动化(Oracle)。 在 EXCEPTION 块中忘记记录用户名。经过一周的调查发现,某人在故意“破坏”文档——仅通过审计日志中的间接迹象才发现这一点。
历史
项目:电子商务。 在故障时,过程将错误记录到 ErrorLog。一次,Log 表被扩展的事务锁定,尝试记录日志引发了嵌套错误,这覆盖了原始原因并清空了错误栈。通过实施额外的批量故障表和多级日志记录进行了修复。