データベースのトランザクション、特にトランザクション分離レベルの理解を定着させる上でまずはAnomalyを起点に話を整理するとわかりやすい。 なぜならトランザクション分離レベルというのは様々あるAnomalyをどこまで許容あるいは防ぐかという度合いだからだ。 しかし自分が見聞きしたデータベース、MySQL関連のトランザクション分離レベルの基本の解説では、明確にAnomalyという用語が使われていないことが多いように感じた。
よってこの記事では、データベースのトランザクションの理解のためにAnomalyの概要をまず整理する。
データベースにおいては並列処理のスループットを上げることは重要である。 並列で処理出来ないと組織でそのデータを同時に参照あるいは更新することが出来ず、1つずつ直列でしか操作が出来ない。
しかしデータを並列で処理する際にはデータ不整合に関する様々な問題が発生し得る。 データベースにおいてデータを並列に処理する上で起こってほしくないそのような問題はAnomalyと呼ばれ、具体的に様々な種類のAnomalyが定義されている。
これらのAnomalyを解決するためにトランザクション分離レベルというものが定義されている。 Anomalyとトランザクション分離レベルはANSI SQLで定義されているもの(ANSI SQLに関する参考記事)でMySQLやInnoDBに固有のものではない。
これらのトランザクション分離レベルをどのように実現するかの具体的な方法論や仕組みは、各データベースやストレージエンジンで異なる。 MySQLであればストレージエンジンごとに解決方法が異なる。
dirty readやnonrepeatable read, phantom readはデータを読み取る際に発生する読み取りのAnomalyであり、それに対しlost updateはデータの書き込みに際して発生するAnomalyとも言える。 書き込みのAnomalyにはdirty writeというAnomalyがあり、これはdirty readしたコミットされていない(ロールバックされうる)データに基づいた書き込みのこと。 書き込みのAnomalyには他にwrite skewというものもある。(write skewについては「データ指向アプリケーションデザイン」が詳しい)
これらのトランザクション分離レベルはデータベースの設定で切り替えることができ、上記一覧で最初に記述したものほど並列度が高く、最後のものが処理としてより直列になる。 つまりトランザクション分離レベルはデータベースにおけるACID特性のうちのIsolation(I)をどこまで厳密にやるかを規定したものと言える。
最初に話したように直列で処理することは処理のスループット低下に繋がるので、データベースを利用する際にどこまで並列度(スループット)を求めるかあるいはデータの整合性を求めるかはトレードオフの関係であり、それはデータベースを利用するアプリケーションに求めるものや特性によって異なる。
ところでACIDのIsolationの説明として、「実行中のトランザクションは(他のトランザクションから)参照出来ない」とありこれは比較的イメージがしやすいと思う。この他に「実行中のトランザクションは(他トランザクションが)変更出来ない」ともある。これはどういう意味だろうか?
これはあるトランザクション(トランザクションaとする)は他トランザクションから影響を受けないということを意味し、実行中のトランザクションaから見ると他のトランザクションは実行されておらず存在していないものとして、トランザクションa実行中は他トランザクション要因のデータの変更が全く無いように振る舞うということを意味する。(その実行中のトランザクションa自身による変更は見える)
つまりトランザクションが開始されるとその開始時点のデータで固定される(データの変更が停止される)ように振る舞うことを意味する。(厳密にはトランザクション開始時点か、そのトランザクション中の最初のselect時点か、どちらのタイミングかという話もあるがそれは別途解説する)
Anomalyへの対応つまりそれぞれのトランザクション分離レベルをどのように実現しているかの具体的な方法論は以下のようなものがある。その詳細、特にMVCCについては別記事にまとめる予定。