問題:
テーブルtable_a
とが与えられた場合、が更新さtable_b
れるたびに、次のような操作を確実に (かつ同時に) 実行する必要があります。table_a
SELECT
からのいくつかの行table_a
。- アプリケーション コードで何かを計算します。
UPDATE
の行table_b
。
このようなことが起こるのを防ぐ必要があります (このシナリオ A と呼びますtable_b
) table_a
。
worker1
から行を取得しますtable_a
。table_a
更新されます。worker2
から行を取得しますtable_a
。worker2
更新しますtable_b
。worker1
更新しますtable_b
。
しかし、これは問題ありません (これをシナリオ B と呼びます) table_b
。
worker1
から行を取得しますtable_a
。table_a
更新されます。worker2
から行を取得しますtable_a
。worker1
更新しますtable_b
。worker2
更新しますtable_b
。
取引:
REPEATABLE READ
1 つの解決策は、すべてをトランザクションでラップすることです。次にworker1
、 のトランザクションはシナリオ A で失敗し、worker2
のトランザクションはシナリオ B で失敗します。シナリオを区別する方法がないため、失敗したトランザクションを再試行するしかありません。
しかし、どちらのシナリオでも無駄です。シナリオ A では、はすでに完全に更新されているworker1
ため、 のトランザクションを再試行したくありません。シナリオ B では、正しいことを行っていたので、そもそも のトランザクションをtable_b
失敗させたくありません。worker2
行のマーキング:
最初から行の主キーがわかっている場合table_b
( :b_id
)、各ワーカーに一意の ID がある場合 ( :worker_id
)、別のことを試すことができます。mark
に列を追加し、table_b
ステップ 1 の前に各ワーカーにこれを実行させます。
UPDATE table_b SET mark = :worker_id WHERE id = :b_id;
WHERE
次に、ステップ 3 で句を追加します。
UPDATE table_b SET ... WHERE ... AND mark = :worker_id;
必要worker1
に応じて、両方のシナリオでステップ 3 の行を更新しません。
ここで行のマーキングは合理的なアプローチですか? 私が見逃している欠点は何ですか?この問題に対する「標準的な」解決策は何ですか?
明確化:私は PostgreSQL を使用しています。