トランザクション分離レベル
Isolation
そもそも何が問題か?
複数のトランザクション間でレコードの書き換えがどう反映されるか?
コミット前のレコードが他のトランザクションから参照・更新されるかどうか。
一度読んだデータを二度読んだ時に同じデータが読めるかどうか。(他トランザクションのコミットにより書き換わった場合に、どうなるか?)
どういう現象が起こるのか?
コミット前の他トランザクションのレコードが見えてしまう。
コミット前の他トランザクションのレコードに書き込んでしまう。
二度読みの時の不整合
二度目に読んだレコードの値が異なる。
一度読んだレコードが消えてしまう。
二度目にレコードが現れてしまう。
参照と更新の順序が互い違いになって不整合になる。(Write skew)
部分的参照・更新による不整合が起こる。
(常に一体としてアトミックにアクセスしなければならないのに、分離されて実行されるため)
書き込みロックしたにもかかわらず、書き換わる
期待されない動作のことを Anomaly (異常)と呼ぶ。
Anomaly の種類
ダーティリード(Dirty read)
他トランザクションのコミット前のデータが読み出されてしまうこと。
ダーティライト(Dirty write)
他トランザクションのコミット前のデータに書き込んでしまうこと。
ノンリピータブルリード(Non-repeatable Read)
二度読み出した時に他トランザクションにより後から書き込まれた異なる値が読み出されてしまうこと。
ファントムリード(Phantom read)
二度読みした時に他トランザクションにより追加されたレコードが見えてしまうこと。
二度読みした時に他トランザクションにより削除されたレコードが見えなくなってしまうこと。
リードスキュー(Read skew)
トランザクション1がxを読んで、次のyを読む前に、トランザクション2がxとyを更新してしまう。トランザクション1がyを読んだ時には、先に読んだxと不整合になっている。
ロストアップデート(Lost Update)
トランザクション1と2が、同時に読み出した値を元に、その値を更新するときに、先に更新した値を上書きしてしまう。
T1 が x を読む。
T2 が x を読む。
T2 が x + a を x に書き戻してコミットする。
T1 が x + b を x に書き戻してコミットする。(上書き)
カーソルロストアップデート(Cursor Lost Update)
FOR UPDATE をしていてもロストアップデートと同様の状態になるもの。(具体的状況がよく分からない)
ライトスキュー(Write skew)
トランザクション1が、読み出したxを元にyを変更する時に、トランザクション2が読み出したyを元にxを変更してしまう。
リードオンリー(Read only)、オブザーブスキュー(Observe skew)
観測者のトランザクション(読み出しのみ)が更新系トランザクション2つの間に割り込んでしまうことで、更新系トランザクション2つの途中経過を読み込んでしまい、時系列的に不整合な状態で読み出してしまう。
更新系トランザクションのみの視点での結果は整合している。
循環参照状態になっているため、そのままではシリアライズができない。
データベースの実装側で防ぐ方法
シリアライズ
そもそも同時に同じリソースを変更するから様々な競合が発生するのであって、トランザクションが開始されたら、他のトランザクション開始をトランザクション終了まですべて待ち状態にすればよい。
スナップショット(バージョン管理)
トランザクションを開始した、あるいは最初のクエリが発生した時間が分かっていれば、その時点のスナップショットを使うことができる。
時刻を使う方法と版番号を使う方法がある。
厳密に考えると時刻は完全ユニーク、シリアル順になるようにする必要がある。
暗黙的ロック
参照・更新したレコード、テーブルに対して自動的にロックを掛ける
依存関係のグラフを作る。
循環参照状態になったらそのトランザクションは失敗する。
プログラム側で防ぐ方法
二度読みしない。
トランザクションの開始直後に読み込み、終了直前に書き込む。
同時に読み出せるものは同時に読み出す。(割り込まれる隙間を作らない)
明示的ロック
意図的にロックすることを宣言する。
テーブルに対してロックする。(レコードの追加、削除、更新を排他制御する。(特に追加))
FOR UPDATE などで、読み出しの時に更新ロックを取得する。
読み書きする順序を一方向にする。循環させない。
そもそも循環するようなデータ更新は何らかの設計ミスが疑われる。
楽観ロック
レコードの更新の時刻や版番号を記録して、最初の参照時とずれていたらやり直す。
更新時刻を使うと同じ時刻になるようなケースで失敗する。
トランザクションの最先端研究 | 分離レベルの追跡・究明―TiDBの分離レベルを理解する(上)
トランザクションをSerializableにする4つの方法
いろんなAnomaly