読者です 読者をやめる 読者になる 読者になる

トランザクションあれこれ

トランザクションの開始と終了

デフォルトにより、MySQL は自動コミットモードが有効な状態で起動します。これは、テーブルを更新(変更)するステートメントを実行したとたん、MySQL がディスク上に更新を格納する、という意味です


START TRANSACTION を利用すると、自動コミットは COMMIT や ROLLBACK を利用してトランザクションを終了するまで無効のままです。

BEGIN と BEGIN WORK は、トランザクションを始める START TRANSACTION のエイリアスとしてサポートされています。

http://dev.mysql.com/doc/refman/5.1/ja/commit.html

標準SQLでは、トランザクションブロック開始時のSTART TRANSACTIONコマンドの発行は必須ではありません。 任意のSQLコマンドが暗黙的にブロックを開始するからです。 PostgreSQLでは、START TRANSACTION(もしくはBEGIN)が実行されていない状態で発行されたコマンドは、その直後に、暗黙的なCOMMITが発行されたかのように動作します。

http://www.postgresql.jp/document/pg820doc/html/sql-start-transaction.html

つまり

  • 自動コミットモード:ON
    • SQLステートメントの直後にコミットを実行する
    • START TRANSACTION(BEGIN/BEGIN WORK)でモードを無効にできる
  • 自動コミットモード:OFF
    • COMMITやROLLBAKを実行するまでが1つのトランザクションで扱われる
    • START TRANSACTIONは明示的にする実行する必要はない

ということ。

独立性

トランザクションシステムが満たすべき4つの性質(ACID)のうち、Isolation(独立性/分離性)に関する話。
MySQL InnoDBSQL標準で定義されている4つのトランザクション分離レベルのすべてが提供されている。

[mysqld]
transaction-isolation = {READ-UNCOMMITTED | READ-COMMITTED
                         | REPEATABLE-READ | SERIALIZABLE}


実践ハイパフォーマンスMySQL」や「InnoDB と SET ... TRANSACTION ISOLATION LEVEL ...」「PostgreSQLドキュメント」を読んでみた。なんとかまとめてみるが、実際にはデータベースの実装により詳細は違うみたい。

Read Uncommitted

トランザクションAでまだコミットされていないSQLステートメント結果をトランザクションBで読み出すことが可能(=dirty read)。

Read Committed

ステートメントが実行される直前までにコミットされたデータのみを参照し、まだコミットされていないデータや、そのステートメントの実行中に別の同時実行トランザクションがコミットした更新は参照しない。 つまり、ステートメント実行を開始した時点のデータベースのスナップショットを参照することになる。

ステートメント開始時点のスナップショットなので、繰り返し不可能な読み出し(unrepeatable read)が発生する。

Repeatable read

トランザクションが開始される前までにコミットされたデータのみを参照する。 コミットされていないデータや、そのトランザクションの実行中に別のトランザクションでコミットされた変更を参照しない。

SQL標準ではファントム読み出し(phantom read)が発生しうる。が、InnoDBでは

一貫した読み取りの中に、READ COMMITTED 分離レベルとの重要な違いがあります:同一トランザクション内の全ての一貫した読み取りは、最初の読み取りで確立された同じスナップショットを読み取ります。このしきたりは、もし同じトランザクション内でいくつかの単純な SELECT ステートメントを発行すると、これらの SELECT ステートメントはお互いに対しても一貫性を持つという事を意味します。

http://dev.mysql.com/doc/refman/5.1/ja/innodb-transaction-isolation.html

となっているので、phantom readは発生しない(はず..)

Serializable

複数のトランザクションが衝突しない順序に並べ替え、直列で実行されたかのように各トランザクションを実行する。

まとめ

トランザクションについていろいろ調べた

  • START TRANSACTION(BEGIN)を明示的に実行せずともトランザクションは開始される
  • SQL標準で分離レベルは規定されているが、細かな挙動はDBの実装によって違う
  • Read Committedはステートメント開始時点のスナップショットを、Repeatable Readはトランザクション中の最初のステートメントで確立したスナップショット、という違いは覚えておくべき


(理解が間違っている可能性はあるし、DBの違いまで考慮してない書き方なので、つっこみ歓迎)