0 / 5
更新消失(ロストアップデート、Lost Update)
二つのトランザクションが同じデータを読み、それぞれ書き換えると、後から書いた値が先に書いた値を上書きし、一方の更新が消える。
二つの販売の操作が混ざって実行される順序をたどる。
4 / 5
T2がT1の値を上書きする
T2も自分の読んだ10から1を引いて9を書く。T1が書いた9を知らずに計算したので、T1の更新を上書きする。
5 / 5
結果:更新消失
販売は二回なのに、在庫は一つしか減っていない。
原因:T2は、T1が9を書く前に読んだ10で計算した。
1 / 4
T1が9を書く
T1がXに9を書く。決済を確認している途中なので、まだCommitしていない。
2 / 4
T2が途中の値を読む
T2が確定していない9を読み、画面に「在庫9個」と表示する。
3 / 4
T1が取り消す
決済が失敗し、T1がRollbackする。在庫は再び10になる。
4 / 4
結果:ダーティリード
T2が見せた9は、一度も確定したことのない値だ。
連鎖ロールバックとの違い:ここでの問題は、確定していない値がすでに画面に出たことだ。連鎖ロールバックは、その値を読んだトランザクションまで一緒にRollbackしなければならないという回復側の問題だ。
4 / 6
T2が振替を確定する
T2がCommitして振替を確定する。実際の合計は200のままだ。
5 / 6
T1がBを読む
T1がBを読むときには振替がすでに終わっていて、Bは150だ。
6 / 6
結果:不整合
T1が読んだAは振替前の値で、Bは振替後の値だ。だから一度も存在しなかった合計250が出た。
参考:この例では、DBに保存された値は正しい。T1が求めた合計だけが辻褄が合わない。
3 / 7
T2が9をもとに8を書く
T2が9から1を引いて8を書く。T1がまだCommitしていない値で計算した。
4 / 7
T1が取り消しを始める
決済が失敗し、T1はRollbackしなければならない。ところが、T1が書いた9の上にT2がすでに8を書いた。T2から元に戻さないと、T1の9を元に戻せない。
5 / 7
T2も取り消される
T2は無効になった9で計算したので、Rollbackする。DBはT2が書いた8を9に戻す。
6 / 7
T1の取り消しが終わる
DBがT1の書いた9を10に戻す。ここでようやく最初の値10に戻る。
7 / 7
結果:連鎖ロールバック
T1がRollbackすると、T1が書いた値を読んだT2もRollbackしなければならなかった。T2の値を読んだT3があれば、T3も続けてRollbackしなければならない。
ダーティリードとの違い:ダーティリードは確定していない値を読んだ結果が問題で、連鎖ロールバックはその値を読んだトランザクションまで次々にRollbackしなければならない点が問題だ。この例ではT2が書いた8まで元に戻した。参考:T2がすでにCommitしていたら、T2はRollbackすることさえできない。このような実行順序を回復不可能なスケジュールという。