任何 SQL 工业解决方案都需要合理的错误处理架构。没有日志记录和仔细的异常处理,特别是在存储过程和批处理脚本中,很难调试复杂的过程。
问题历史: 标准 SQL 允许最小的错误处理(例如,RETURN 和停止处理)。现代扩展(T-SQL, PL/pgSQL, PL/SQL 等)提供了完整的错误处理结构(TRY/CATCH, EXCEPTION)。
问题: 没有显式的错误处理“沉没”,而管理员很难确定故障原因,尤其是在大规模更改或与外部系统交互时。经常需要将错误记录到单独的表中以进行后续分析。
解决方案: 使用 TRY/CATCH (T-SQL) 或 EXCEPTION (PL/pgSQL) 的工具包以及自己的日志记录表。别忘了将诊断信息(错误代码、错误文本、请求参数和时间)发送到日志中。
代码示例(T-SQL,MS SQL Server):
CREATE TABLE ErrorLog ( ErrorId INT IDENTITY PRIMARY KEY, ErrorTime DATETIME, ProcedureName NVARCHAR(128), ErrorMessage NVARCHAR(MAX), ErrorNumber INT, ErrorState INT, ErrorSeverity INT ); CREATE PROCEDURE usp_ProcessOrders AS BEGIN BEGIN TRY -- 业务逻辑 UPDATE Orders SET Status = 'PROCESSED' WHERE Status = 'NEW'; END TRY BEGIN CATCH INSERT INTO ErrorLog ( ErrorTime, ProcedureName, ErrorMessage, ErrorNumber, ErrorState, ErrorSeverity ) VALUES ( GETDATE(), ERROR_PROCEDURE(), ERROR_MESSAGE(), ERROR_NUMBER(), ERROR_STATE(), ERROR_SEVERITY() ); THROW; END CATCH END
代码示例(PL/pgSQL,PostgreSQL):
BEGIN -- 你的代码 EXCEPTION WHEN OTHERS THEN INSERT INTO error_log(ts, proc_name, err_text) VALUES(now(), 'my_proc', SQLERRM); RAISE; END;
关键特点:
仅仅捕获错误并在不向外部传递信息的情况下终止过程是否足够?
不。没有显式的日志记录或传播错误,就无法捕捉和分析故障原因。重要的是要在日志中详细记录错误,或者至少将其传播出去(THROW/RAISE)。
能否仅使用内置 SQL Server/DBMS 日志来识别用户过程中的所有错误?
部分可以。许多错误如果在应用程序或过程中“捕获”并处理,就不会出现在服务器日志中。对于业务逻辑,维护自己详细的事件日志是有益的。
如果过程只使用简单的 DML 操作,是否一定要使用 TRY/CATCH(或 EXCEPTION)?
如果过程影响重要数据,参与关键链并且必须记录异常情况,则必须使用。即使是“安全”的操作也可能由于外部限制(唯一性、外键、死锁等)导致错误。
在项目中,错误未记录,仅向用户显示。在大规模故障中,管理员可能需要数小时寻找“看不见”的问题。
优点:
缺点:
任何关键错误都在日志表中记录详细信息(时间、过程、参数、错误代码),并在系统的票证中引用。
优点:
缺点: