トランザクションあれこれ
トランザクションの開始と終了
デフォルトにより、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 InnoDBはSQL標準で定義されている4つのトランザクション分離レベルのすべてが提供されている。
[mysqld] transaction-isolation = {READ-UNCOMMITTED | READ-COMMITTED | REPEATABLE-READ | SERIALIZABLE}
「実践ハイパフォーマンスMySQL」や「InnoDB と SET ... TRANSACTION ISOLATION LEVEL ...」「PostgreSQLドキュメント」を読んでみた。なんとかまとめてみるが、実際にはデータベースの実装により詳細は違うみたい。
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は発生しない(はず..)