InnnoDBのトランザクションの扱いについてまとめた

トランザクション分離レベル

ファントムリード

3度SELECTを行い件数を取得するTx1クエリがあるとする。

Tx1クエリのCommit前に、1行別のTx2クエリトランザクションによってCommitされたとする。

Tx1クエリトランザクションでは、このトランザクション内で他のTx2クエリのCommit後、取得するレコードの数が増えてしまう。

このように他のトランザクションCommitによって読み込むレコードの数が増減することを言う。

 

ダーティリード

ファントムリードとは違い、他変更トランザクションがCommitされる前にすでに影響を他トランザクションに及ぼすことを言う。

この場合、変更された状態のものを他トランザクションは取得するがRollbackされることでその変更はなくなるといった不整合が起きたりする。

ファントムリードとは違い、1つのレコードに対して別トランザクションが競合した際にどうなるかについての挙動を指している。

 

ファジーリード(ノンリピータブルリード)

ファントムリードと影響を受けるタイミングは同じで、別トランザクションのCommit以降に影響を受ける。

ファントムリードとは違い、1つのレコードに対して別トランザクションが競合した時にどうなるかについての挙動を指している。(ファントムリードは複数レコードに対する影響を指している。)

1つのレコードを取得するトランザクションがCommitされる前に別トランザクションからのCommitで変更されたとき、その変更後のデータを取得してしまうと言う影響のこと。

 

MVCCとは?

最新のレコードが更新されると、未CommitのトランザクションにはUNDOログという古い更新前レコードを参照させる仕組みのこと。

 

MCCCによって何が解決する?

ファントムリード、ファジーリード、ダーティリードの発生を防げる。

 

ノンロッキングリードとロッキングリードとは?

ノンロッキングリードでは、最新のレコードにロックがかかっていたとしても古いレコードにMVCCの仕組みによってアクセスできるためロックの競合が起きない。

ロッキングリードは、DELETEやUPDATEクエリを発行する際に起こり、最新のデータへアクセスする必要があるためロックの競合は起きる。

これらはトランザクション分離レベルにおけるREPEATABLE-READとREAD-COMMITEDにおいて実行されるクエリの種類によって変化する。

 

ロッキングリードの注意点

- 自身がロックしているレコードは最新のものが見えるため過去の状態のレコードを期待していると予期せぬ結果が返ってくる。

- つまり、SELECT(ノンロッキング)-> UPDATE(ロッキング)-> SELECT(ロッキング)だと最初と最後の見ているレコードのバージョンが違うことになる。

 

MVCCが適用されないロッキングリードではどうやってファントムリードを防ぐのか?

ロッキングリード時は、ダーティリードとファジーリードはそもそも同一レコードに対してロックがかかっているので他トランザクションは実行できないため防がれる。

ただし、ファントムリードはロックしている行以外が差し込まれた時にクエリの実行される範囲によっては影響を受けるというものであるためロックだけでは防げない。

MVCCも機能しないロッキングリードではこうした場合、ネクスキーロックによってファントムリードを防ぐ。

 

ネクスキーロックとは

特定範囲の行に対するトランザクションがあった時、各行の次に挿入される予定のレコード部分をロックする。

ここにレコードが現状存在するわけではないが、あると仮定してロックがされる。これによって新しいレコードが挿入できなくなり、ファントムリードは防がれる。