SQL 第 3 弾: トランザクションとロックで「壊れない送金処理」を作る

口座間の送金を題材に、複数の更新をまとめて成功か失敗かにするトランザクション、同時更新を守る行ロック(FOR UPDATE)、不正な状態を DB で防ぐ CHECK 制約、更新履歴を残すトリガーを PL/pgSQL で実装します。2 つのターミナルでロック待ちも観察します。

中級約 60 分Azure 実環境

ラボ概要

このラボでは、社内のポイント送金機能を任されたバックエンド担当の想定で、「残高が消える」「二重に送られる」「マイナスになる」を DB の仕組みで防ぐ方法を実機で身につけます。

ブラウザで開く IDE の PostgreSQL に、口座テーブル accounts(10 口座 × 100,000 円、合計 1,000,000 円)が入っています。送金関数を PL/pgSQL で書き、わざと失敗させて「途中で止まっても残高の合計は変わらない」ことを確かめ、2 つのターミナルで同じ口座を同時に更新してロック待ちを観察します。

学習目標:

  • BEGIN / COMMIT / ROLLBACK と、関数内の例外による自動ロールバック(原子性)
  • SELECT ... FOR UPDATE による行ロックで、同時更新の競合を防ぐ
  • CHECK 制約で「残高は 0 以上」を DB 側で保証する
  • トリガーで更新履歴(監査ログ)を自動で残す
  • pg_locks / pg_stat_activity でロック待ちを観察する
前提知識:
  • UPDATE / SELECT の基本と、「SQL 入門」「SQL 中級」ラボ相当の知識
完了条件:
  • balance >= 0 の CHECK 制約、transfer(from_id, to_id, amount) 関数(FOR UPDATE を使用)、transfer_audit への記録トリガーがあること
  • 3,000 円の送金で残高が 97,000 / 103,000 になり合計が 1,000,000 のままで、残高不足の送金はエラーで何も変わらないこと
  • locks_notes.md にロック待ちの観察結果が書かれていること

ラボの構成

  1. 1ブラウザ IDE を開いて口座テーブルを確認する
  2. 2まず「壊れる」送金を体験する
  3. 3CHECK 制約で「マイナス残高」を DB が拒否するようにする
  4. 4送金関数を PL/pgSQL で作る
  5. 5トリガーで更新履歴を自動記録する
  6. 62 つのターミナルでロック待ちを観察する
  7. 7判定を実行する
  8. 8発展(任意)と考察

詳細な手順は、ラボ開始後に画面内のガイドとして表示されます。

手順のプレビュー(最初のステップ)

1. ブラウザ IDE を開いて口座テーブルを確認する

  • ラボ画面の ブラウザ IDE を開く をクリックし、表示されているパスワードでサインインする
  • README.md を読み、Terminal → New Terminal でターミナルを開いて PostgreSQL に接続する
psql "$DATABASE_URL"
SELECT * FROM accounts ORDER BY id;
SELECT sum(balance) FROM accounts;   -- 1000000

> 注: このラボでは「合計 1,000,000 円が常に保たれるか」を正しさの目安にします。送金は片方を減らしてもう片方を増やすだけなので、合計は決して変わらないはずです。

残り 7 セクションの手順は、ラボを開始すると画面内に表示されます

構成図

構成図

参考リソース

このラボが対応する試験の模擬問題集

本番形式の問題で理解度を確認できます。各試験とも先頭 15 問は無料です。

DP-300Azure Database Administrator練習テスト 2 回・全 160 問