MySQLのトランザクションについての備忘録
会社の先輩にDBについて質問したとき、そういえばトランザクションって何気なく使ってるけどちゃんと調べたこと無いなと思ったので調べてみました。
トランザクションとは?
日本語にすると
「transaction とは、commit や roll back ができる、不可分な処理の単位です
transaction が複数の変更をデータベースに実施した際、transactionがコミットされたらすべての変更が成功し、ロールバックされたらすべての変更がもとに戻されます」となります。
基本的には START TRANSACTION と COMMIT, ROLLBACK で囲まれたステートメント群が1つのトランザクションとみなされます。
自動コミットモード
MySQLはデフォルトでは自動コミットモードが有効になった状態で動作する。つまり、各ステートメントがそれぞれトランザクションのように動作します。
START TRANSACTION でトランザクションを開始すると、そのトランザクションが終了するまで自動コミットは無効となり、トランザクションが終了すると、自動コミットモードはトランザクション開始前の状態に戻ります。
ロールバックできないステートメントもある
データベースやテーブル構造を変更するデータ定義言語ステートメントはロールバックできません。
(トランザクション内に含めることはできるが、ロールバックでキャンセルできない)
そもそもトランザクションはデータ更新の一連の流れを一つのものとみなしたいから存在している概念なため、これは納得です。
暗黙的なコミットを発生させるステートメント
データベースオブジェクトを定義または変更するデータ定義言語(DDL)ステートメント
mysql データベース内のテーブルを暗黙的に仕様または変更するステートメント
トランザクション制御及びロックステートメント
データロードステートメント
管理ステートメント
レプリケーション制御ステートメント
1,2 に関しては、ロールバックできないステートでも出てきたのでそういうことか!という感じです。
3 に関してはちょっと罠感がありました。。。
例えば下記のような操作をした場合
START TRANSACTION;
INSERT INTO user (id, name) VALUES (1, 'hoge');
START TRANSACTION; -- 前のステートメントが暗黙的にコミットされる
INSERT INTO user (id, name) VALUES (1, 'fuga');
ROLLBACK;
最終的に ROLLBACK で変更が取り消させるのは2回目の INSERT 文だけで、id:1, name: 'hoge' の user レコードはコミットされてしまいます。
SAVEPOINT, ROLLBACK TO SAVEPOINT, RELEASE SAVEPOINT
SAVEPOINT
SAVEPOINT ステートメントは、identifier を指定して、トランザクションのセーブポイントを設定する事ができます。
SAVEPOINT identifier;
現在のトランザクションに同じ名前を持つセーブポイントが存在する場合は上書きとなります。
ROLLBACK TO SAVEPOINT
セーブポイント設定時に指定した identifier を指定して、トランザクションを途中までロールバックする事ができます。
例えば
START TRANSACTION;
INSERT INTO user (id, name) VALUES (1, 'user_1');
INSERT INTO user (id, name) VALUES (2, 'user_2');
INSERT INTO user (id, name) VALUES (3, 'user_3');
SAVEPOINT sp1;
INSERT INTO user (id, name) VALUES (4, 'user_4');
INSERT INTO user (id, name) VALUES (5, 'user_5');
INSERT INTO user (id, name) VALUES (6, 'user_6');
user に複数のレコードを挿入しながら、途中でセーブポイントを設定した場合。
ROLLBACK TO sp1;
上記を実行することで、後半の3件のレコード挿入分のみを取り消すことができます。
トランザクションは終了していないため、このあとに何も指定せず ROLLBACK を実行すれば、前半の3件のレコード挿入も取り消されるし、 COMMIT を実行すれば前半3件のレコード挿入のみ確定されます。
RELEASE SAVEPOINT
設定したセーブポイントを削除することができます。
このときコミットやロールバックは発生しません。
RELEASE SAVEPOINT identifier;
終わり
MySQLの公式Docを読んでトランザクションの勉強をしてみました。
暗黙的なコミットを発生させるステートメントやセーブポイントについては知らなかったので、こんなのもあるんだ、、、って感じでした。
公式Doc読むの大事。