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「順番をそろえる ロックの順番」で覚えます。ブラウザの中のシミュレーターで、本物と同じように打って確かめられます。
すべてのレベルが、プラチナ以上のプランで遊べます。