トランザクション内で2つのINSERTを実行。1つ目の直後にサーバーが落ちたら、1つ目のデータはどうなる?
解説
正解は「両方とも保存されない」です。トランザクションは「全部成功するか、全部なかったことにするか」の二択で動きます。途中まで実行された状態でサーバーが落ちた場合、COMMIT が完了していないため、再起動時にデータベースが自動的にROLLBACK(巻き戻し)を行います。1つ目の INSERT が「実行された」としても、COMMIT されていなければ保存は確定していません。「1つ目だけ保存される」を選んだ方は、SQL文が実行された時点でデータが確定すると考えたかもしれません。しかし、トランザクション内ではCOMMITが確定の合図です。「再起動後に続きが実行される」ということもありません。データベースは中断されたトランザクションを再開する仕組みを持っていません。トランザクションの「原子性」とは何かトランザクションにはACID特性と呼ばれる4つの性質があります。その中でもこの問題に直結するのが原子性(Atomicity)です。原子性とは、トランザクション内の操作が「すべて実行される」か「1つも実行されない」かのどちらかしかないという性質です。「原子」という名前は、それ以上分割できない最小単位という意味から来ています。途中の状態でデータが残ることはありません。COMMITとROLLBACKの役割トランザクションの結末は2つだけです。COMMIT — すべての変更を確定する。これが実行されて初めてデータが永続化されるROLLBACK — すべての変更を取り消す。明示的に実行するほか、異常終了時にはデータベースが自動で行う重要なのは、INSERT や UPDATE を実行しただけではデータは確定していないという点です。トランザクション内でのこれらの操作は「仮の状態」であり、COMMIT によって初めて本物になります。クラッシュからの復旧を支える仕組み — WALではデータベースはどうやってクラッシュ後に「なかったこと」にできるのでしょうか。多くのRDBMS(PostgreSQL、MySQLなど)はWAL(Write-Ahead Logging)という仕組みを使っています。WALの基本的な考え方はシンプルです。データを実際に書き換える前に、「何をするか」をログファイルに先に書き出します。クラッシュが起きた場合、再起動時にこのログを確認し、COMMITされていないトランザクションの変更を取り消します。この仕組みがあるからこそ、原子性が保証されています。AUTO COMMITモードとの違い多くのデータベースはデフォルトでAUTO COMMITが有効になっています。この場合、各SQL文が個別のトランザクションとして扱われ、実行直後に自動でCOMMITされます。つまりBEGINで明示的にトランザクションを開始しない限り、1文ごとに確定されていきます。「トランザクションを使ったことがない」と思っている方も、実はAUTO COMMITのおかげで毎回トランザクションの恩恵を受けています。複数の操作をまとめて成功・失敗させたい場合に、明示的にBEGIN〜COMMITで囲む必要があるということです。