ストアドプロシージャでは、特別な構文を使用してエラーを処理することが必要です。
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ブロックでユーザー名をログに記録するのを忘れました。一週間の調査の結果、誰かが意図的に文書を「壊して」いたことが判明しましたが、監査ログの間接的な証拠によってのみ分かりました。
逸話
プロジェクト:E-commerce。 プロシージャが失敗時にErrorLogにエラーを書き込みました。一度、Logテーブルがトランザクションの拡大によりロックされ、ログ記録の試みがネストされたエラーを引き起こし、元の原因が上書きされてエラースタックがクリアされました。重大な障害用の追加テーブルと多層ログ記録を導入して修正しました。