トランザクション分離という概念を知りました
トランザクションとは?
「命令ひとまとまり」のこと
例えば、「AさんがBさんに100万円振り込む」という処理について、
- Aさんの口座残高を100万円減らす
- Bさんの口座残高を100万円増やす
の二つの処理を行う必要があります。
この時、1. だけ実行されて、2. が実行されないと大問題になります。
偉い人総出で謝罪会見必至です。
そのため、複数の命令を一つのパッケージとしてまとめ上げ、「もし途中で止まったら、一連の命令が全部実行されなかったことにする」必要が出てきます。
それを実現するのがトランザクションです。
- トランザクションスタート
- Aさんの口座残高を100万円減らす
- Bさんの口座残高を100万円増やす
- コミットする
とすることで、例えば3の実行が失敗してBさんの口座残高を増やせなかった時、2でやったAさんの口座残高更新も巻き戻すことができるようになります。
トランザクションは、ACID原則を満たしているべきとされます。
んで、マルチスレッドで同時に複数のクエリが飛んできた時、このうちの「独立性(Isolation)」が脅かされます。
並列トランザクションの問題
トランザクション処理中に、ある二つの命令の間に別のトランザクションがテーブルを書き換えてしまい、他のトランザクションの影響を受ける、というシナリオですね。
具体的には、ファントムリードとか、ダーティリードとか、ノンリピータブルリードとかの問題が起こります。詳しくはこちら
https://qiita.com/momotaro98/items/ad859ec2934ee98540fb
トランザクション分離
この問題を回避するのが、トランザクション分離です。
具体的には、
- READ UNCOMMITTED
- READ COMMITTED
- REPEATABLE READ
- SERIALIZABLE
の四つに分類されております。
下に行けば行くほど強力な分離です。
というか、一個下に行くと、並列トランザクションの問題を一個づつ潰せるようになります。
トランザクション分離の仕組み
トランザクション分離は、トランザクション分離実行中に、データベースにロックをかけることで実現しています。
それぞれ、
- READ COMMITTED:書き込み処理中に、行ロックをかける
- REPEATABLE READ:読み込み・書き込み処理中に行ロックをかける
- SERIALIZABLE:読み込み・書き込み処理中にテーブルロックをかける
という感じでできてるらしい
考察
ここからは考察、というか妄想
トランザクション分離レベルを上げるデメリットは?
ロック対象が広くなるから、パフォーマンスが悪化しそう?
あと、デッドロックが発生しやすくなる...んでしょうか。
でもデッドロックはテーブルの構造じゃなくて、テーブルの扱いで避けるべきもの...な気もする。
まあ詳しくは現場ででくわしてからな