110 WHERE id = 1; ・トランザクション B(開始〜データ更新) postgres=> BEGIN; postgres=*> UPDATE hoge.fuga SET val = 120 WHERE id = 1; ・トランザクション A(コミット) postgres=*> COMMIT; ・トランザクション B(コミット失敗) postgres=*> COMMIT; ERROR: change conflicts with another transaction, please retry: (OC000) 同じデータ行を更新しようとした場合 [1] 25
110 WHERE id = 1; ・トランザクション B(開始〜データ更新) postgres=> BEGIN; postgres=*> UPDATE hoge.fuga SET val = 120 WHERE id = 1; ・トランザクション A(コミット) postgres=*> COMMIT; ・トランザクション C(開始〜データ更新) postgres=> BEGIN; postgres=*> UPDATE hoge.fuga SET val = 130 WHERE id = 1; 同じデータ行を更新しようとした場合 [2] 28
please retry: (OC000) postgres=> ROLLBACK; WARNING: there is no transaction in progress ・トランザクション C(コミット・データ参照 →トランザクション Cの値で上書きされている) postgres=*> COMMIT; postgres=> SELECT * FROM hoge.fuga; id | val ----+----- 1 | 130 (1 row) 同じデータ行を更新しようとした場合 [2] 29
id = 1; ・トランザクション B(コミット失敗・ロールバック) postgres=*> COMMIT; ERROR: change conflicts with another transaction, please retry: (OC000) postgres=> ROLLBACK; WARNING: there is no transaction in progress ・トランザクション C(コミット失敗) postgres=*> COMMIT; ERROR: change conflicts with another transaction, please retry: (OC000) 同じデータ行を更新しようとした場合 [3] 33
please retry: (OC000) postgres=> ROLLBACK; WARNING: there is no transaction in progress ・トランザクション C(コミット) postgres=*> COMMIT; 更新対象行がトランザクション毎に異なる場合 [2] 41
TxB は競合扱い→ COMMIT 時に失敗❌(その後リトライしても B は 8 万のまま) 書き込みスキュー異常の回避 ⚫BEGIN ◎SELECT A ... FOR UPDATE ◎SELECT B ... FOR UPDATE →100000・80000 COMMIT❌ ⚫BEGIN COMMIT⭕ ⚫BEGIN 46 ◎A+B<200000 →UPDATE A=A+20000 ◎A+B<200000 →UPDATE B=B+20000 ◎SELECT A ◎SELECT B → 120000・ 80000 ◎SELECT A ... FOR UPDATE ◎SELECT B ... FOR UPDATE →100000・80000 TxA TxB
WHERE number = 10000001 FOR UPDATE; number | name | amount ----------+----------+-------- 10000001 | 佐藤一郎 | 100000 (1 row) postgres=*> SELECT * FROM hoge.account WHERE number = 11000001 FOR UPDATE; number | name | amount ----------+----------+-------- 11000001 | 佐藤二朗 | 80000 (1 row) 書き込みスキュー異常の回避 48
WHERE number = 10000001 FOR UPDATE; number | name | amount ----------+----------+-------- 10000001 | 佐藤一郎 | 100000 (1 row) postgres=*> SELECT * FROM hoge.account WHERE number = 11000001 FOR UPDATE; number | name | amount ----------+----------+-------- 11000001 | 佐藤二朗 | 80000 (1 row) 書き込みスキュー異常の回避 49