メモ > 技術 > データベース: MySQL > トランザクション
トランザクション
■トランザクション
・BEGIN または START TRANSACTION でトランザクションを開始する(意味はどちらも同じ)
・COMMIT でトランザクションを終了し、変更は永続化される
・ROLLBACK でトランザクションを終了し、変更は取り消される
■トランザクション分離レベル
MySQLのInnoDBのトランザクション分離レベルは、デフォルトで REPEATABLE READ となっている
REPEATABLE READ はトランザクション開始後にテーブルの値を変更しても、SELECT で参照できるのは変更前の値
これにより、例えば予約システムなどで
1. トランザクションを開始する
2. 現在の予約数を取得する
3. 取得した予約数が一定件数以下なら予約データを登録する。一定件数以上ならエラーにする
という処理を書いたとき、2で取得できるデータは1時点のもの
つまり3に到達した時点で予約数はさらに増えている可能性がある
つまり「定員が100人のイベントに105人予約されてしまった」という現象が起こりうる
トランザクション分離レベルを「READ COMMITTED」にしておけば、操作もとでコミットされた時点で他端末からも変更後の値を参照できるようになり、Oracle、PostgreSQL、SQL Server などではこれがデフォルト設定となっている
そちらの方が直感的なので、変更しておくと余計なトラブルを防ぐことができる(常に変更して良いものかは要検討)
以下のSQLを発行することで、その接続だけトランザクション分離レベルを変更できる
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
MySQLでトランザクションの4つの分離レベルを試す - FAT47の底辺インフラ議事録
http://d.hatena.ne.jp/fat47/20140212/1392171784
MySQLのデフォルトのトランザクション分離レベルは SELECT がスナップショットを参照する - ngyukiの日記
http://ngyuki.hatenablog.com/entry/2013/02/02/202558
[RDBMS][SQL]トランザクション分離レベルについて極力分かりやすく解説 - Qiita
https://qiita.com/PruneMazui/items/4135fcf7621869726b4b
InnoDBにおけるトランザクション分離レベルについて - Qiita
https://qiita.com/taisho6339/items/1097c67a54cedf9504d6
現在のトランザクション分離レベルは、以下のSQLで確認できる
SELECT @@GLOBAL.tx_isolation, @@tx_isolation;
第47回 トランザクション分離レベルを変更する:MySQL道普請便り|gihyo.jp … 技術評論社
https://gihyo.jp/dev/serial/01/mysql-road-construction-news/0047
MySQLのautocommitとトランザクション分離レベルのメモ - Qiita
https://qiita.com/rubytomato@github/items/562a1638191aacaeb333
MySQLがこのような挙動になっているのは、バイナリログの整合性を担保するための名残らしい
MySQL InnoDBのネクストキーロック おさらい - SH2の日記
http://d.hatena.ne.jp/sh2/20090112
以下、トランザクション分離レベルの挙動を検証したときのメモ
2つの端末からアクセスするので、それぞれ「mysql1>」「mysql2>」と表記する
■REPEATABLE READ のまま(デフォルト)
mysql1> BEGIN;
mysql2> BEGIN;
mysql1> SELECT * FROM test;
mysql1> UPDATE test SET text = 'TEST2 UPDATED!' WHERE id = 2;
mysql1> SELECT * FROM test; … 更新を確認できる
mysql2> SELECT * FROM test; … 他端末からは更新を確認できない
mysql1> COMMIT;
mysql2> SELECT * FROM test; … 他端末からは更新を確認できない
mysql2> COMMIT;
mysql2> SELECT * FROM test; … 他端末からも更新を確認できる
■READ COMMITTED に変更
mysql1> SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
mysql1> BEGIN;
mysql2> SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
mysql2> BEGIN;
mysql1> SELECT * FROM test;
mysql1> UPDATE test SET text = 'TEST2 UPDATED!' WHERE id = 2;
mysql1> SELECT * FROM test; … 更新を確認できる
mysql2> SELECT * FROM test; … 他端末からは更新を確認できない
mysql1> COMMIT;
mysql2> SELECT * FROM test; … 操作もとでコミットされた時点で、他端末からも更新を確認できる
■ロールバック
【忘備録】InnoDBでもロールバックが効かない文
http://mementomori.info/%E3%80%90%E5%BF%98%E5%82%99%E9%8C%B2%E3%80%91innodb%E3%81%A7%E3%82%82%E3%83%...
MySQLでTruncateはRollback出来るのか? | SRIA BLOG - 宮城県仙台市のWEBシステム開発・スマホアプリ開発
https://www.sria.co.jp/blog/2014/08/mysql-can-do-rollback-truncate/
MySQLの「暗黙のトランザクションコミット」対策:トランザクション中でも安全にCREATE TABLEなどをする方法 - Qiita
https://qiita.com/suin/items/3527297a22632f3db31d
MySQL :: MySQL 5.6 リファレンスマニュアル :: 13.3.3 暗黙的なコミットを発生させるステートメント
https://dev.mysql.com/doc/refman/5.6/ja/implicit-commit.html