このページの2つのバージョン間の差分を表示します。
両方とも前のリビジョン 前のリビジョン 次のリビジョン | 前のリビジョン 次のリビジョン 両方とも次のリビジョン | ||
mariadb:10.4:transaction [2020/10/20 14:38] y2sunlight [SQL文による手動トランザクション] |
mariadb:10.4:transaction [2020/11/19 17:10] y2sunlight [MySQLi による手動トランザクション] |
||
---|---|---|---|
行 1: | 行 1: | ||
====== MariaDB10.4 トランザクション ====== | ====== MariaDB10.4 トランザクション ====== | ||
+ | phpMyAdmin 4.9.0.1 (MariaDB 10.4.6) | ||
+ | |||
--- // | --- // | ||
行 5: | 行 7: | ||
関連記事 | 関連記事 | ||
- | * [[xampp: | ||
* [[mariadb: | * [[mariadb: | ||
* [[mariadb: | * [[mariadb: | ||
行 12: | 行 13: | ||
* MariaDB10.4 トランザクション | * MariaDB10.4 トランザクション | ||
- | 以下「MySQL」は「MariaDB」に読み替えて下さい | + | 以下「MySQL」は「MariaDB」に読み替えて下さい。 |
---- | ---- | ||
- | MySQLではトランザクションセーフなテーブル(InnoDBなど)と非トランザクションセーフなテーブル(MyISAMなど)を作る事ができます。手動トランザクションが使えるのはトランザクションセーフなテーブルだけです。 MyISAMなどの非トランザクションセーフなテーブルの場合は、データベースの変更は直ちにコミットされます。本章ではストレージエンジンとしてInnoDBを使ったテーブルを対象とします。 | + | ===== 概要 ===== |
+ | |||
+ | MySQLではトランザクションセーフなテーブル(InnoDBなど)と非トランザクションセーフなテーブル(MyISAMなど)を作る事ができます。手動トランザクションが使えるのはトランザクションセーフなテーブルだけです。 MyISAMなどの非トランザクションセーフなテーブルの場合は、データベースの変更は直ちにコミットされます。 | ||
+ | |||
+ | 本章ではストレージエンジンとしてInnoDBを使ったテーブルを対象として、トランザクションについて説明します。InnoDBでは、以下のトランザクション分離レベルをサポートしています: | ||
+ | |||
+ | * READ UNCOMMITTED --- 非コミット読み取り | ||
+ | * READ COMMITTED --- コミット済み読み取り | ||
+ | * REPEATABLE READ --- 再読み込み可能読み取り | ||
+ | * SERIALIZABLE --- 直列化 | ||
+ | |||
+ | ここでは、これらの分離レベルの違いをサンプルプログラムを使用して実感しながら説明したいと思います。 | ||
+ | |||
+ | \\ | ||
- | ==== MySQLのトランザクション ==== | + | ===== MySQLのトランザクション |
MySQLはデフォルトで自動トランザクション機能(自動コミットモード)が有効です。本編ではMySQLiを使っているので、プログラムの途中で自動コミットモードを切り替える場合は、次のようにします。 | MySQLはデフォルトで自動トランザクション機能(自動コミットモード)が有効です。本編ではMySQLiを使っているので、プログラムの途中で自動コミットモードを切り替える場合は、次のようにします。 | ||
行 80: | 行 94: | ||
> [[https:// | > [[https:// | ||
- | ==== SQL文による手動トランザクション ==== | + | \\ |
+ | |||
+ | ===== SQL文による手動トランザクション ===== | ||
ブラウザからサンプルプログラム(sqlfile.php)を実行します。 | ブラウザからサンプルプログラム(sqlfile.php)を実行します。 | ||
行 97: | 行 114: | ||
); | ); | ||
INSERT INTO syain VALUES(1,' | INSERT INTO syain VALUES(1,' | ||
- | ; | + | #; |
-- トランザクション開始 ------------------ | -- トランザクション開始 ------------------ | ||
-- SET AUTOCOMMIT = 0; | -- SET AUTOCOMMIT = 0; | ||
行 113: | 行 130: | ||
</ | </ | ||
- | 10行目のセミコロン(;)だけの行はブラウザ上で改行する為に使用しています。誤りではありません。 | + | 10行目の |
実行結果 | 実行結果 | ||
行 125: | 行 142: | ||
この例で、START TRANSACTION文を1行目に移動して実行すると、奇妙な現象が起こります。ロールバックが効かなくなるのです。これは、DROP TABLE文により暗黙のコミットが発生してトランザクションが終了している為です。それ以降は自動コミットモードになるのでROLLBACK文は無効になります。この現象はDROP TABLEやCREATE TABLEなどのDDL文の場合に発生します。トランザクションを設計する場合は注意する必要があります。 | この例で、START TRANSACTION文を1行目に移動して実行すると、奇妙な現象が起こります。ロールバックが効かなくなるのです。これは、DROP TABLE文により暗黙のコミットが発生してトランザクションが終了している為です。それ以降は自動コミットモードになるのでROLLBACK文は無効になります。この現象はDROP TABLEやCREATE TABLEなどのDDL文の場合に発生します。トランザクションを設計する場合は注意する必要があります。 | ||
- | ==== MySQLi による手動トランザクション ==== | + | \\ |
+ | |||
+ | ===== MySQLi による手動トランザクション | ||
ブラウザからサンプルプログラム(sqlfile.php)を実行します。 | ブラウザからサンプルプログラム(sqlfile.php)を実行します。 | ||
行 133: | 行 152: | ||
</ | </ | ||
- | <file sql transaction1b.sql> | + | <file sql transaction1b.sql> |
+ | -- テーブル作成 ------------------------- | ||
DROP TABLE IF EXISTS syain; | DROP TABLE IF EXISTS syain; | ||
CREATE TABLE syain ( | CREATE TABLE syain ( | ||
行 142: | 行 162: | ||
); | ); | ||
INSERT INTO syain VALUES(1,' | INSERT INTO syain VALUES(1,' | ||
- | ; | + | #; |
- | #トランザクション開始 ------------------ | + | |
- | #EVAL $mysqli-> | + | -- トランザクション開始 ------------------ |
+ | -- EVAL $mysqli-> | ||
EVAL $mysqli-> | EVAL $mysqli-> | ||
SELECT * FROM syain; | SELECT * FROM syain; | ||
- | # テーブルの更新 | + | -- テーブルの更新 |
UPDATE syain SET syain_age = syain_age + 1; | UPDATE syain SET syain_age = syain_age + 1; | ||
INSERT INTO syain VALUES(2,' | INSERT INTO syain VALUES(2,' | ||
SELECT * FROM syain; | SELECT * FROM syain; | ||
- | # トランザクション終了 ----------------- | + | -- トランザクション終了 ----------------- |
EVAL $mysqli-> | EVAL $mysqli-> | ||
SELECT * FROM syain; | SELECT * FROM syain; | ||
行 160: | 行 181: | ||
上のスクリプトファイルにはEVAL文が含まれています。EVALに続く式(例えば:$mysqli-> | 上のスクリプトファイルにはEVAL文が含まれています。EVALに続く式(例えば:$mysqli-> | ||
- | 実行結果 | + | === 実行結果 |
[{{: | [{{: | ||
行 169: | 行 190: | ||
MySQLiを利用してデータベースをアクセスする場合、移植性による理由から、begin_transaction/ | MySQLiを利用してデータベースをアクセスする場合、移植性による理由から、begin_transaction/ | ||
+ | |||
+ | \\ | ||
==== トランザクションの分離レベル ==== | ==== トランザクションの分離レベル ==== | ||
行 188: | 行 211: | ||
<file sql transaction2a.sql> | <file sql transaction2a.sql> | ||
- | # テーブル作成 ------------------------- | + | -- テーブル作成 ------------------------- |
DROP TABLE IF EXISTS syain; | DROP TABLE IF EXISTS syain; | ||
CREATE TABLE syain ( | CREATE TABLE syain ( | ||
行 197: | 行 220: | ||
); | ); | ||
INSERT INTO syain VALUES(1,' | INSERT INTO syain VALUES(1,' | ||
- | ; | + | #; |
- | #トランザクション開始 ------------------ | + | |
+ | -- トランザクション開始 ------------------ | ||
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; | SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; | ||
- | #SET TRANSACTION ISOLATION LEVEL READ COMMITTED; | + | -- SET TRANSACTION ISOLATION LEVEL READ COMMITTED; |
- | #SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; | + | -- SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; |
- | #SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; | + | -- SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; |
START TRANSACTION; | START TRANSACTION; | ||
- | EVAL # | + | EVAL # トランザクションA開始; |
SELECT * FROM syain; | SELECT * FROM syain; | ||
- | EVAL # | + | EVAL # ここで他のトランザクションがデータを更新する; |
EVAL sleep(5); | EVAL sleep(5); | ||
SELECT * FROM syain; | SELECT * FROM syain; | ||
SELECT * FROM syain LOCK IN SHARE MODE; | SELECT * FROM syain LOCK IN SHARE MODE; | ||
- | # トランザクション終了 ----------------- | + | -- トランザクション終了 ----------------- |
COMMIT; | COMMIT; | ||
- | EVAL # | + | EVAL # トランザクションA終了; |
EVAL sleep(5); | EVAL sleep(5); | ||
SELECT * FROM syain; | SELECT * FROM syain; | ||
- | |||
</ | </ | ||
行 241: | 行 264: | ||
<file sql transaction2b.sql> | <file sql transaction2b.sql> | ||
- | #トランザクション開始 ------------------ | + | -- トランザクション開始 ------------------ |
START TRANSACTION; | START TRANSACTION; | ||
EVAL # | EVAL # | ||
- | # テーブルの更新 | + | -- テーブルの更新 |
INSERT INTO syain VALUES(2,' | INSERT INTO syain VALUES(2,' | ||
UPDATE syain SET syain_age = syain_age + 1; | UPDATE syain SET syain_age = syain_age + 1; | ||
行 252: | 行 275: | ||
EVAL sleep(5); | EVAL sleep(5); | ||
- | # トランザクション終了 ----------------- | + | -- トランザクション終了 ----------------- |
ROLLBACK; | ROLLBACK; | ||
EVAL # | EVAL # | ||
行 261: | 行 284: | ||
以下の順でSQLスクリプトを実行します。2番目のスクリプトは5秒以内に実行します。 | 以下の順でSQLスクリプトを実行します。2番目のスクリプトは5秒以内に実行します。 | ||
- | - < | + | - '' |
- | - < | + | - '' |
実行結果 | 実行結果 | ||
行 283: | 行 306: | ||
<file sql transaction2c.sql> | <file sql transaction2c.sql> | ||
- | # 自動コミットモード ------------------- | + | -- 自動コミットモード ------------------- |
- | # レコード挿入 | + | -- レコード挿入 |
INSERT INTO syain VALUES(2,' | INSERT INTO syain VALUES(2,' | ||
SELECT * FROM syain; | SELECT * FROM syain; | ||
- | # レコード更新 | + | -- レコード更新 |
UPDATE syain SET syain_age = syain_age + 1; | UPDATE syain SET syain_age = syain_age + 1; | ||
SELECT * FROM syain; | SELECT * FROM syain; | ||
行 297: | 行 320: | ||
以下の順でSQLスクリプトを実行します。2番目のスクリプトは5秒以内に実行します。 | 以下の順でSQLスクリプトを実行します。2番目のスクリプトは5秒以内に実行します。 | ||
- | - < | + | - '' |
- | - < | + | - '' |
実行結果 | 実行結果 | ||
行 316: | 行 339: | ||
<file sql transaction2c.sql> | <file sql transaction2c.sql> | ||
- | # 自動コミットモード ------------------- | + | -- 自動コミットモード ------------------- |
- | # レコード挿入 | + | -- レコード挿入 |
INSERT INTO syain VALUES(2,' | INSERT INTO syain VALUES(2,' | ||
SELECT * FROM syain; | SELECT * FROM syain; | ||
- | # レコード更新 | + | -- レコード更新 |
UPDATE syain SET syain_age = syain_age + 1; | UPDATE syain SET syain_age = syain_age + 1; | ||
SELECT * FROM syain; | SELECT * FROM syain; | ||
行 328: | 行 351: | ||
以下の順でSQLスクリプトを実行します。2番目のスクリプトは5秒以内に実行します。 | 以下の順でSQLスクリプトを実行します。2番目のスクリプトは5秒以内に実行します。 | ||
- | - < | + | - '' |
- | - < | + | - '' |
実行結果 | 実行結果 | ||
行 346: | 行 369: | ||
<file sql transaction2c.sql> | <file sql transaction2c.sql> | ||
- | # 自動コミットモード ------------------- | + | -- 自動コミットモード ------------------- |
- | # レコード挿入 | + | -- レコード挿入 |
INSERT INTO syain VALUES(2,' | INSERT INTO syain VALUES(2,' | ||
SELECT * FROM syain; | SELECT * FROM syain; | ||
- | # レコード更新 | + | -- レコード更新 |
UPDATE syain SET syain_age = syain_age + 1; | UPDATE syain SET syain_age = syain_age + 1; | ||
SELECT * FROM syain; | SELECT * FROM syain; | ||
</ | </ | ||
- | ブラウザから http:// | + | ブラウザから |
実行結果 | 実行結果 |