3秒でわかる
トランザクション中の変更を確定させ、他の接続からも見える正式なデータとしてデータベースへ書き込む操作。取り消しはできません。
30秒図解
もう少し詳しく
どういうものか
トランザクションの中で行った INSERT や UPDATE、DELETE を確定させる命令。COMMIT を実行した時点で変更は正式なものになり、他の接続からも見えるようになる。確定した内容は障害が起きても失われず、あとから取り消すこともできない。取り消したい場合は ROLLBACK を、COMMIT より前に実行する必要がある。
COMMIT が返るまでの間、変更は自分の接続の中にだけ存在する。別の接続から同じ行を SELECT しても、まだ古い値が返る。
なぜ必要か
送金処理を考えると分かりやすい。A の残高を減らす UPDATE と、B の残高を増やす UPDATE の 2 つは、両方成立するか、両方無かったことになるかのどちらかでなければならない。片方だけ反映されると、お金が消える。トランザクションで囲んで最後に COMMIT すれば、途中で落ちた変更が中途半端に残らない。
具体例
START TRANSACTION;
UPDATE accounts SET balance = balance - 5000 WHERE id = 1;
UPDATE accounts SET balance = balance + 5000 WHERE id = 2;
-- ここまでは自分の接続からしか見えない
COMMIT; -- 2つの更新が同時に確定する途中で誤りに気づいた場合は下記のようにする。
START TRANSACTION;
DELETE FROM orders WHERE created_at < '2020-01-01';
SELECT ROW_COUNT(); -- 想定より多ければ
ROLLBACK; -- 消さずに戻すつまずきやすいところ
MySQL や PostgreSQL のクライアントは既定で自動コミットが有効になっている。つまり 1 文ごとに勝手に COMMIT されるため、DELETE の直後に ROLLBACK と打っても手遅れになる。取り消せる状態にしたいなら、先に START TRANSACTION を打つ必要がある。
もう 1 つは、COMMIT せずに接続を閉じてしまう例。多くの環境では未確定の変更は破棄され、書いたはずのデータが消えたように見える。
長時間 COMMIT しないまま行を掴み続けるのも問題になる。その行を触りたい他の処理がロック待ちで止まり、待ち時間の上限を超えるとエラーで落ちる。トランザクションは短く区切るのが基本になる。
似た用語との違い
Git の commit は履歴を 1 つ積む操作で、内容は自分の手元に残る。データベースの COMMIT は「元に戻せる状態を終わらせる」操作で、方向が逆になる。名前が同じでも混同しないこと。