LoginSignup
13
16

More than 3 years have passed since last update.

絵や表で見ておぼえるSQLトランザクションと分離レベル

Last updated at Posted at 2020-02-10

本記事ではどのトランザクション分離レベルにすることで、どんな現象を防ぐことができるかについて。何度も見聞きするがよく忘れてしまうので、図説して絵で確認していきます。

トランザクションとは?

トランザクションの基本的要点は複数の手順を単一の「全てかなしか」の操作にまとめ上げることです。 (参考:PostgreSQL 11.5文書)

簡単に言うと

  • 1つの作業単位として扱う一連の操作の集まりです
  • トランザクション内の操作は全て実行されるか、または全て実行されないです

トランザクションが活躍する場面でよく使われる例は、銀行の振り込みです。
例えばAさんがBさんに1万円を振り込むとき、

  • Aさんの口座から出金されたが、Bさんへの口座への入金に失敗
  • Bさんへの口座への入金に成功しているが、Aさんの口座から出金されていない

といった問題を防ぐため、出金と入金の処理をまとめてトランザクションにします。

transaction.png
図を見ると、処理は2つありますがそれらをまとめてトランザクションとしています。
処理結果は、どちらも成功の場合のみトランザクションの処理を全て実行するようにしていますね。

これで、入出金の失敗が防げるようになりました。

トランザクションによって起こりうる現象

こんな便利なトランザクションですが、使うことで起こる可能性のあるよく知られた現象が3つあります。

1. ダーティリード
2. ノンリピータブルリード(ファジーリード)
3. ファントムリード

ダーティリード

別のトランザクション(絵ではトランザクションB)でまだコミットされていないデータを、他のトランザクション(絵ではトランザクションA)内で読み込んでしまう現象
dirty-reads.png
まだ処理が終わっていないデータを読み込んでしまっています。
トランザクションAが失敗した場合
「Aさんの口座から1万円をマイナス」されないこと(ロールバック)になりますが、
Cさんは「Aさんの口座から1万円をマイナス」された結果を見てしまいます

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

あるトランザクション(絵ではトランザクションB)でデータを複数回読み取っている途中で、
他のトランザクション(絵ではトランザクションA)でデータを書き換え(更新し)てしまい、
途中から違う結果のデータを読み取ってしまう現象
nonrepeatable-read.png

ファントムリード

あるトランザクション(絵ではトランザクションB)の途中で、
他のトランザクション(絵ではトランザクションA)によってデータが挿入/削除されてしまい、
途中から読み込むデータ(の数)が異なってしまう現象
phantom-read.png

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

トランザクションによって起こってしまう3つの問題を見てきました。
いずれもトランザクション中に他の処理が入ってしまうことで起きる問題です。

これらの問題を防ぐために、トランザクションはトランザクション中の処理に対して他の処理がどの程度介入できるかを設定することができます。

これをトランザクション分離レベルと呼びます。トランザクション分離レベルは4つあります。

  1. Read Uncommited
  2. Read Commited(PostgreSQLのデフォルト)
  3. Repeatable Read(MySQLのデフォルト)
  4. Serializable

下に行くほど強い分離レベルと呼ばれ、「ダーティリード、ノンリピータブルリード、ファントムリード」の問題を防ぐことが可能になります。
isolation-level.png
※Serializableが必ず良いと言うわけではありません

13
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
16