编程数据库开发者

如何在 SQL 的存储过程(stored procedures)中实现有效的错误处理和调试程序?有哪些机制用于捕获和记录错误?这些方法在不同的数据库管理系统中是否有所不同?

用 Hintsage AI 助手通过面试

回答。

在存储过程中可以且应该使用特殊结构来处理错误。

在 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 处理,例如,解析或编译错误会在进入 TRY 之前导致事务回滚。
  • 为了记录信息,重要的是要有独立的错误表。
  • 应尽可能记录更多信息:错误文本、编号、用户名、操作参数。
  • 在不同的数据库管理系统中,语法和功能是不同的。

反转问题。

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 表被扩展的事务锁定,尝试记录日志引发了嵌套错误,这覆盖了原始原因并清空了错误栈。通过实施额外的批量故障表和多级日志记录进行了修复。