MySQLのような同時実行性の問題については以前に聞いたことがあります。Postgresではそうではありません。
デフォルトのREAD COMMITTED
トランザクション分離レベルの組み込み行レベルロックで十分です。
データを変更するCTE(MySQLにもないもの)を使用した単一のステートメントをお勧めします。あるテーブルから別のテーブルに値を直接渡すことが必要な場合(必要な場合)に便利だからです。coupon
テーブルから何も必要ない場合は、個別のUPDATE
and INSERT
ステートメントを使用したトランザクションも使用できます。
WITH upd AS (
UPDATE coupon
SET used = true
WHERE coupon_id = 123
AND NOT used
RETURNING coupon_id, other_column
)
INSERT INTO log (coupon_id, other_column)
SELECT coupon_id, other_column FROM upd;
それはする必要があります珍しい複数のトランザクションの試みは、同じクーポンを利用する事。彼らにはユニークな番号がありますね。同時に複数のトランザクションが同時に試行されることは、はるかにまれです。(たぶん、アプリケーションのバグか、システムをゲームしようとしている誰か?)
とにかく、何が起こっても、1つのトランザクションでUPDATE
のみ成功します。は更新前に各ターゲット行の行レベルのロックを取得します。並行トランザクションが同じ行を試行すると、行のロックが表示され、ブロッキングトランザクションが終了するまで(または)待機してから、ロックキューの最初になります。UPDATE
UPDATE
ROLLBACK
COMMIT
競合状態になる可能性はありません。
同じトランザクションにより多くの書き込みを行うか、1つのトランザクションよりも多くの行をロックしない限り、デッドロックの可能性はありません。
INSERT
ケアフリーです。なんらかの間違いによりcoupon_id
すでにlog
テーブルに存在している(そしてUNIQUEまたはPK制約がにあるlog.coupon_id
)場合、一意の違反の後にトランザクション全体がロールバックされます。DBでの不正な状態を示します。上記のステートメントがlog
テーブルに書き込む唯一の方法である場合、それが発生することはありません。