トランザクション分離レベル・リード現象
リード現象(Read phenomena)
ダーティリード、リピータブルリード、ファントムリードをちゃんと理解してからトランザクション分離レベルを理解しよう
ダーティリード(Dirty reads)
COMMITされていないトランザクションでの変更を他トランザクションがReadすることができてしまう現象。
Flow | トランザクション1(T1) | トランザクション2(T2) | 説明 |
---|---|---|---|
Step1 | SELECT Tag FROM Articles WHERE Id = 1; | T1は"Container"でReadする | |
Step2 | UPDATE Articles SET Tag = 'Docker' WHERE id = 1; | T2はCommitしない | |
Step3 | SELECT Tag FROM Articles WHERE Id = 1; | T1は"Docker"でReadされる(ダーティリード現象) | |
Step4 | ROLLBACK; | T2はロールバック可能 |
ノンリピータブルリード(Non-repeatable reads)
他トランザクション(T2)がコミットにより対象レコードを更新した場合、1トランザクション(T1)中でReadするレコードデータが異なってしまう現象。
Flow | トランザクション1(T1) | トランザクション2(T2) | 説明 |
---|---|---|---|
Step1 | SELECT * FROM Articles; | T1は全2レコードをクエリする | |
Step2 | UPDATE Articles SET Tag = 'Docker' WHERE id = 1; | ここではT1は対象レコードを読み取れない | |
Step3 | COMMIT; | T2がコミットされる | |
Step4 | SELECT Tag FROM Articles WHERE Id = 1; | T1は"Docker"でReadされる(ノンリピータブルリード現象) |
ファントムリード(Phantom reads)
他トランザクション(T2)がコミットにより新規レコード追加(または削除)をした場合、1トランザクション(T1)中でReadするテーブルデータが異なってしまう現象。
Flow | トランザクション1(T1) | トランザクション2(T2) | 説明 |
---|---|---|---|
Step1 | SELECT * FROM Articles; | T1は全2レコードをクエリする | |
Step2 | INSERT INTO Articles(Id,Title,Tag) VALUES (3, 'How to start Go', 'Go'); | T2で新規レコードを追加する | |
Step3 | COMMIT; | T2がコミットされる | |
Step4 | SELECT * FROM Articles; | T1は全3レコードをクエリする(ファントムリード現象) |
(個人用メモ)
ノンリピータブルリードは update、ファントムリードは insert/delete が対象?
トランザクション分離レベル VS リード現象 対応表
トランザクション分離レベル | Dirty reads | Non-repeatable reads | Phantoms reads |
---|---|---|---|
Read Uncommitted | 発生し得る | 発生し得る | 発生し得る |
Read Committed | 発生しない | 発生し得る | 発生し得る |
Repeatable Read | 発生しない | 発生しない | 発生し得る |
Serializable | 発生しない | 発生しない | 発生しない |
MySQL のデフォルトは Repeatable Read。
insert デッドロック(ギャップロック)発生時、Read Committed に変える事を検討する。(ファントムリードが発生する事を許容する)
<参考>
MySQL InnoDBのギャップロックによるデッドロックを解明する
トランザクション分離レベル
あるセッションのトランザクションで更新されたデータが、他セッションからのどう見えるかを設定するパラメータ値です。
トランザクション分離レベル - Wikipedia
MySQLでInsert into Selectでデッドロック発生
SERIALIZABLE(直列化可能)
複数の並行に動作するトランザクションそれぞれの結果が、いかなる場合でも、それらのトランザクションを時間的重なりなく逐次実行した場合と同じ結果となる。
このような性質を直列化可能性(Serializability)と呼ぶ.SERIALIZABLEは最も強い分離レベルであり、最も安全にデータを操作できるが、相対的に性能は低い。
ただし同じ結果とされる逐次実行の順はトランザクション処理のレベルでは保証されない。
REPEATABLE READ(読み取り対象のデータを常に読み取る) ※MySQL デフォルト
ひとつのトランザクションが実行中の間、読み取り対象のデータが途中で他のトランザクションによって変更される心配はない。
同じトランザクション中では同じデータは何度読み取りしても毎回同じ値を読むことができる。
ただし ファントム・リード(Phantom Read) と呼ばれる現象が発生する可能性がある。
ファントム・リードでは、並行して動作する他のトランザクションが追加したり削除したデータが途中で見えてしまうため、処理の結果が変わってしまう。
READ COMMITTED(確定した最新データを常に読み取る) ※insert デッドロック発生時、この設定に変える事を考える
他のトランザクションによる更新については、常にコミット済みのデータのみを読み取る。
MVCC はREAD COMMITTEDを実現する実装の一つである。
ファントム・リード に加え、非再現リード(Non-Repeatable Read)と呼ばれる、同じトランザクション中でも同じデータを読み込むたびに値が変わってしまう現象が発生する可能性がある。
READ UNCOMMITTED(確定していないデータまで読み取る)
他の処理によって行われている、書きかけのデータまで読み取る。
PHANTOM 、 NON-REPEATABLE READ 、さらに ダーティ・リード(Dirty Read) と呼ばれる現象(不完全なデータや、計算途中のデータを読み取ってしまう動作)が発生する。
トランザクションの並行動作によってデータを破壊する可能性は高いが、その分性能は高い。