SELECT … FOR UPDATE の使い方

書き換える行を、先に決まった順でつかむ

書き方

SELECT id FROM 表 WHERE id IN (…) ORDER BY id FOR UPDATE;
… FOR NO KEY UPDATE;(キーの列を変えない書き換え。外部キーの確かめとぶつからない)
… FOR UPDATE NOWAIT;(つかまれていたら待たずにエラー)
… FOR UPDATE SKIP LOCKED;(つかまれた行は飛ばす)

SELECT に FOR UPDATE を付けると、出てきた行をトランザクションの終わりまでつかみます(ほかの接続の UPDATE・DELETE・FOR UPDATE は待たされます)。ORDER BY を付けると、並べた順につかみます。2 つの処理が同じ行を逆の順番で書き換えると、お互いを待ってデッドロックになります。どの処理も、最初に「番号の小さい順に FOR UPDATE でつかむ」と決めておけば、後から来た方が先頭の行で待つだけで、輪になりません。表を LOCK TABLE で丸ごとつかんでも起きなくなりますが、関係のない行の処理まで一列に並ばせてしまいます。

例

BEGIN;
SELECT id FROM ledger WHERE id IN (2, 1) ORDER BY id FOR UPDATE;
UPDATE ledger SET balance = balance - 300 WHERE id = 2;
UPDATE ledger SET balance = balance + 300 WHERE id = 1;
COMMIT;

実際に打って練習する

障害対応(PostgreSQL)コースの Lv14「順番をそろえる ロックの順番」で覚えます。ブラウザの中のシミュレーターで、本物と同じように打って確かめられます。

すべてのレベルが、プラチナ以上のプランで遊べます。

PostgreSQL の障害対応で使う構文一覧へ戻る