やあ、今日もデータベースと格闘してる?
PostgreSQLでストアドプロシージャや関数を書き始めると、必ずと言っていいほどぶち当たる壁があるよね。「処理の途中でエラーが起きたとき、どうやってスマートに後始末するか」っていう問題だ。
今日は、PL/pgSQLにおける「例外処理」の作法について、現場の知見を交えて話そうと思う。マニュアルを読めば載っているような基本の話から、ちょっとした「実務のコツ」まで、肩の力を抜いて読んでみてほしい。
—
なぜ、例外処理(Exception Handling)が必要なのか?
初心者の頃は、エラーが起きても「まあ、投げっぱなしでいいか」と思いがちだ。でも、データの一貫性が命の現場でそれをやると、目も当てられない惨事になる。
例えば、銀行の送金処理中にエラーが起きて、引き落としだけ完了して入金がされなかったら?……想像しただけで冷や汗が出るよね。PL/pgSQLの例外処理は、「不測の事態でも、最低限の安全装置を働かせるための生命線」なんだ。
—
1. エラーを自分で投げる:RAISE文
まずは基本の「RAISE」から。これはエラーを意図的に発生させるための命令だ。
RAISE EXCEPTION ‘ユーザーID % は存在しません’, user_id;
ここでポイントなのが、`%` を使ったプレースホルダー。これを使わずに文字列結合で頑張るコードを見かけるけど、読みづらい上にバグの温床になる。素直に `%` を使おう。
ちなみに、開発中なら `RAISE NOTICE` を使うのもおすすめだ。これは処理を止めずにログだけ吐いてくれる。デバッグの時に `SELECT` 文をあちこちに仕込むより、ずっとスマートだよ。
—
2. エラーを捕まえて無害化する:EXCEPTIONブロック
ここからが本題だ。処理の一部でエラーが起きても、トランザクション全体を失敗させたくない時、`BEGIN … EXCEPTION … END` ブロックが役に立つ。
DO $$
BEGIN
— 何らかの危険な処理
INSERT INTO users (id, name) VALUES (1, ‘Alice’);
EXCEPTION
WHEN unique_violation THEN
— ユニーク制約違反ならログを吐いて無視する、といった制御が可能
RAISE NOTICE ‘このIDは既に使われています。スキップします。’;
END $$;
現場で気をつけるべき「落とし穴」
この `EXCEPTION` ブロックには、一つだけ重大な注意点がある。
「EXCEPTIONブロックに入ると、そのブロック内の処理は自動的にロールバックされる」
つまり、ブロックの中でどれだけ `INSERT` や `UPDATE` を積み重ねていても、最後でエラーをキャッチした瞬間、そのブロック内でやったことはすべて「なかったこと」になるんだ。
「エラーを捕まえてから、ログテーブルにエラーログを書き込もう!」と思って同じトランザクション内で INSERT しても、そのログさえも消えてしまう。これにハマって夜を明かすエンジニアを何人も見てきたよ。ログを残したいなら、`dblink` を使って別セッションで書き込むか、そもそもエラーを出さない設計にするのが鉄則だね。
—
3. 実践的な使い方:エラーコードを分類する
`WHEN` 句を使ってエラーの種類を絞り込むのは、現場の必須スキルだ。全部 `WHEN OTHERS` で片付けるのはやめよう。あれは「何が起きたか分からない」と言っているのと同じだからね。
よく使うのはこのあたりかな。
- `unique_violation`: 重複キーエラー(INSERTのバッティングなど)
- `foreign_key_violation`: 外部キー制約エラー
- `check_violation`: CHECK制約エラー
例えば、外部キー制約に引っかかった時だけ特定の処理をしたいなら、こんな風に書く。
BEGIN
DELETE FROM departments WHERE id = target_id;
EXCEPTION
WHEN foreign_key_violation THEN
RAISE EXCEPTION ‘この部署にはまだ社員が所属しています。先に社員を移動させてください。’;
END;
—
まとめ:結局のところ「予測」がすべて
例外処理は強力な武器だけど、乱用するとコードが複雑になり、処理速度も落ちる。
僕がいつも心がけているのは、「例外処理に頼りすぎない設計」だ。そもそもエラーが起きないようにチェックを入れるのが一番の正義。その上で、どうにも防げない不可抗力や、境界条件のギリギリを攻める時にだけ `EXCEPTION` を使う。
これが、メンテナンス性の高い、後輩に感謝されるコードを書くコツだよ。
どうかな、少しはイメージが湧いたかな?もし現場で「こんな時はどうすればいい?」という複雑なケースに遭遇したら、またいつでも聞いてくれ。データベースの世界は深いけれど、論理さえ押さえれば必ず攻略できるからさ。
それじゃ、また現場で会おう!
コメント