MySQL トランザクション
トランザクションを使うと複数のクエリをまとめて1つの処理として扱うことができる。処理の途中でエラーになって処理を取り消したいような場合はROLLBACKをすることで変更内容を元に戻すことができる。
トランザクションはデフォルトのMyISAM形式のテーブルでは使用できない。トランザクションが使用できるテーブルにはInnoDB,BDBなどがある。以下ではInnoDBを使って説明する。
START TRANSACTION以降のクエリをDBに反映させてトランザクションを完了する場合は以下のようにする。
途中でエラーが発生する等してSTART TRANSACTION以降のクエリを取り消したい場合はROLLBACKする。
通常のトランザクション処理の動作を表1に示す。
表1 トランザクションの挙動(COMMITする場合)
トランザクションをROLLBACKする時の挙動を表2に示す。
表2 トランザクションの挙動(ROLLBACKする場合)
図1 トランザクションの流れ
トランザクションはデフォルトのMyISAM形式のテーブルでは使用できない。トランザクションが使用できるテーブルにはInnoDB,BDBなどがある。以下ではInnoDBを使って説明する。
1.InnoDBテーブルの作成
新規に作るテーブルをInnoDBにするには、以下のようにする。
mysql> CREATE TABLE friends (id SERIAL, name VARCHAR(30)
NOT NULL, address VARCHAR(100), birthday DATETIME) TYPE=InnoDB;
既存のテーブルをInnoDBに変更する場合は以下のとおり。
mysql> ALTER TABLE friends TYPE = INNODB;
2.トランザクションの開始と完了およびROLLBACK
トランザクションを開始する。これ以降に入力されたSQLクエリはトランザクションとして扱われる。トランザクションが終った場合はCOMMIT(DBに結果を反映)かROLLBACK(トランザクション開始前の状態に戻す)をする。mysql> START TRANSACTION;
START TRANSACTION以降のクエリをDBに反映させてトランザクションを完了する場合は以下のようにする。
mysql> COMMIT;
途中でエラーが発生する等してSTART TRANSACTION以降のクエリを取り消したい場合はROLLBACKする。
mysql> ROLLBACK;
3.実際にやってみた時の挙動
実際にトランザクションを使ってみた時の挙動を以下にまとめる。通常のトランザクション処理の動作を表1に示す。
- No.2でトランザクションを開始する
- No.3でテーブルにレコードを追加する
- No.4でレコードを表示させると、スレッドBからは追加されたレコードがまだ見えない。これはトランザクションがまだ完了(commit)していないため(*1)。
- No.5でトランザクションを完了(commit)させるとDBに反映されてスレッドBからも見えるようになる。
(*1) トランザクションで操作した結果は、トランザクションが完了するまで他のトランザクションからは見えないようになっている。この独立性があるおかげで、トランザクション中の中途半端なデータを参照されることはなくなる。
表1 トランザクションの挙動(COMMITする場合)
No. |
スレッドA |
スレッドB |
---|---|---|
1 |
mysql> select id,name from friends; +----+--------+ | id | name | +----+--------+ | 1 | tomita | +----+--------+ 1 row in set (0.00 sec) |
mysql> select id,name from friends; +----+--------+ | id | name | +----+--------+ | 1 | tomita | +----+--------+ 1 row in set (0.00 sec) |
2 |
mysql> START TRANSACTION; Query OK, 0 rows affected (0.00 sec) |
|
3 |
mysql> INSERT INTO friends (name, address, birthday) VALUES("suzuki", "Kamata xxxx", "2006-05-13 12:34:56"); Query OK, 1 row affected (0.00 sec) |
|
4 |
mysql> select id,name from friends; +----+--------+ | id | name | +----+--------+ | 1 | tomita | | 2 | suzuki | +----+--------+ 2 rows in set (0.00 sec) |
mysql> select id,name from friends; +----+--------+ | id | name | +----+--------+ | 1 | tomita | +----+--------+ 1 row in set (0.00 sec) |
5 |
mysql> COMMIT; Query OK, 0 rows affected (0.01 sec) |
|
6 |
mysql> select id,name from friends; +----+--------+ | id | name | +----+--------+ | 1 | tomita | | 2 | suzuki | +----+--------+ 2 rows in set (0.00 sec) |
mysql> select id,name from friends; +----+--------+ | id | name | +----+--------+ | 1 | tomita | | 2 | suzuki | +----+--------+ 2 rows in set (0.00 sec) |
トランザクションをROLLBACKする時の挙動を表2に示す。
- No.2でトランザクションを開始する
- No.3でレコードを追加する。
- No.5でROLLBACKするとトランザクション内のクエリ(No.3)が取り消されているのがNo.6で確認できる。
表2 トランザクションの挙動(ROLLBACKする場合)
No. |
スレッドA |
スレッドB |
---|---|---|
1 |
mysql> select id,name from friends; +----+--------+ | id | name | +----+--------+ | 1 | tomita | | 2 | suzuki | +----+--------+ 2 rows in set (0.00 sec) |
mysql> select id,name from friends; +----+--------+ | id | name | +----+--------+ | 1 | tomita | | 2 | suzuki | +----+--------+ 2 rows in set (0.00 sec) |
2 |
mysql> START TRANSACTION; Query OK, 0 rows affected (0.00 sec) |
|
3 |
mysql> INSERT INTO friends (name, address, birthday) VALUES("tanaka", "Kamata xxxx", "2006-05-13 12:34:56"); Query OK, 1 row affected (0.00 sec) |
|
4 |
mysql> select id,name from friends; +----+--------+ | id | name | +----+--------+ | 1 | tomita | | 2 | suzuki | | 3 | tanaka | +----+--------+ 3 rows in set (0.00 sec) |
mysql> select id,name from friends; +----+--------+ | id | name | +----+--------+ | 1 | tomita | | 2 | suzuki | +----+--------+ 2 rows in set (0.00 sec) |
5 |
mysql> ROLLBACK; |
|
6 |
mysql> select id,name from friends; +----+--------+ | id | name | +----+--------+ | 1 | tomita | | 2 | suzuki | +----+--------+ 2 rows in set (0.00 sec) |
mysql> select id,name from friends; +----+--------+ | id | name | +----+--------+ | 1 | tomita | | 2 | suzuki | +----+--------+ 2 rows in set (0.00 sec) |