見出し画像

MySQLのトランザクションについての備忘録

会社の先輩にDBについて質問したとき、そういえばトランザクションって何気なく使ってるけどちゃんと調べたこと無いなと思ったので調べてみました。


トランザクションとは?

Transactions are atomic units of work that can be committed or rolled back. When a transaction makes multiple changes to the database, either all the changes succeed when the transaction is committed, or all the changes are undone when the transaction is rolled back.

https://dev.mysql.com/doc/refman/8.0/en/glossary.html#glos_transaction

日本語にすると
「transaction とは、commit や roll back ができる、不可分な処理の単位です
transaction が複数の変更をデータベースに実施した際、transactionがコミットされたらすべての変更が成功し、ロールバックされたらすべての変更がもとに戻されます」となります。

基本的には START TRANSACTION COMMIT, ROLLBACK で囲まれたステートメント群が1つのトランザクションとみなされます。

自動コミットモード

MySQLはデフォルトでは自動コミットモードが有効になった状態で動作する。つまり、各ステートメントがそれぞれトランザクションのように動作します。
START TRANSACTION でトランザクションを開始すると、そのトランザクションが終了するまで自動コミットは無効となり、トランザクションが終了すると、自動コミットモードはトランザクション開始前の状態に戻ります。

ロールバックできないステートメントもある

データベースやテーブル構造を変更するデータ定義言語ステートメントはロールバックできません。
(トランザクション内に含めることはできるが、ロールバックでキャンセルできない)
そもそもトランザクションはデータ更新の一連の流れを一つのものとみなしたいから存在している概念なため、これは納得です。

暗黙的なコミットを発生させるステートメント

  1. データベースオブジェクトを定義または変更するデータ定義言語(DDL)ステートメント

  2. mysql データベース内のテーブルを暗黙的に仕様または変更するステートメント

  3. トランザクション制御及びロックステートメント

  4. データロードステートメント

  5. 管理ステートメント

  6. レプリケーション制御ステートメント

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読むの大事。

この記事が気に入ったらサポートをしてみませんか?