SQLにおけるエラー処理とロギングの組織は、複雑なビジネスプロセスの発展と共に特に重要になりました。エラーが発生した場合に実行を停止するだけでなく、障害の事実を記録し、可能であれば作業を継続することが重要です。最初の頃、SQLは高度なtry-catch機能を持っておらず、各データベース管理システム(DBMS)が独自のメカニズムを提供していました。
問題の歴史:
初期のSQL標準では、ストアドプロシージャ内でエラーを捕捉するための組み込み演算子がありませんでした。後に、プロバイダーはMicrosoft SQL ServerのTRY...CATCHやMySQLのHANDLERなどの構造を導入し、データベースレベルでより柔軟に作業プロセスを制御できるようにしました。
問題:
エラーは不正なデータやシステムの原因によって発生する可能性があります。ストアドプロシージャでエラーの捕捉と記録が実装されていない場合、デバッグやメンテナンスが非常に困難になります。また、ビジネスオペレーションの実行を不要に中断しないために、重大なエラーと処理されたエラーを区別できる必要があります。
解決策:
現代のシステムでは、エラーの収集とロギングの構造を導入するべきです。別々のログテーブルを作成し、TRY...CATCH(SQL Server)やDECLARE ... HANDLER(MySQL)を使用し、例外に関する詳細情報を保存して、後で障害の原因を分析します。
コード例(SQL Server):
CREATE PROCEDURE dbo.UpdateCustomer @CustomerID INT, @NewName NVARCHAR(100) AS BEGIN BEGIN TRY UPDATE Customers SET Name = @NewName WHERE CustomerID = @CustomerID; END TRY BEGIN CATCH INSERT INTO ErrorLog (ErrorMessage, ErrorSeverity, ErrorTime) VALUES (ERROR_MESSAGE(), ERROR_SEVERITY(), GETDATE()); THROW; END CATCH END;
主な特徴:
TRY...CATCH(またはハンドラー)ブロック内で捕捉できるエラーの種類はすべてですか?
いいえ、すべてのエラーを捕捉できるわけではありません。たとえば、サーバーの致命的な障害などは捕捉できません。「Attention」タイプのエラーや接続の障害はトランザクション処理の範囲外です。
エラーが発生した場合、トランザクションを使用しないとプロシージャ内の未コミットの変更はどうなりますか?
変更は一部分だけがコミットされ、一部の更新がデータベースに入り、一部が失われる可能性があります。整合性の欠如を避けるためには、トランザクションを常に使用することをお勧めします。
BEGIN TRY BEGIN TRANSACTION; --...コード COMMIT; END TRY BEGIN CATCH ROLLBACK; END CATCH
CATCHブロック内から別のコンテキストからエラーを記録するためにINSERT EXECを使用できますか?
必ずしもではありません:INSERT EXECは、すでにアクティブなトランザクションがある場合など、一部のコンテキストで禁止されており、これによって二次的なエラーが発生する可能性があります。エラーの詳細をローカルに収集し、後で単一のINSERTで記録する方が良いでしょう。
クライアントはRAISERRORだけを使用し、ロギングがなかったため、エラーは保存されず分析されませんでした。
プラス:
マイナス:
TRY...CATCHとErrorLogテーブルを使用し、エラーの時間、コード、ユーザー、テキスト、およびトレースを記録します。
プラス:
マイナス: