トランザクションの処理を取り消して開始前の状態に戻す操作。
ロールバック(ROLLBACK)とは、トランザクション内で行った変更をすべて取り消して、開始前の状態に戻す操作のことです。トランザクションとは「ひとまとまりにして扱うべき複数の処理」のことで、その途中で何か問題が起きたときに使います。
身近な例で考えると、文書編集中の「元に戻す(Ctrl+Z)」をまとめて実行するのに似ています。作業中の変更を全部キャンセルして、編集を始める前のきれいな状態に戻すイメージです。あるいは、鉛筆の下書きを消しゴムで全部消す、と考えても分かりやすいです。
上のツールで▶ボタンを押すと、銀行振込の途中で障害が起き、ROLLBACKで暫定値の変更が取り消されて開始前の残高に戻る流れを確認できます。
ロールバックがどうやって開始前の状態を取り戻すのか、その仕組みを見てみましょう。鍵になるのは「ログ」(=更新の記録)です。
取り消しの流れは次のとおりです。
・更新前の値を記録:データを書き換える前に、「変える前はいくつだったか」をログに残しておく
・暫定値で作業:実際の更新は作業用の一時領域(暫定値)で進める。確定済みの値はまだ動かさない
・ログを見て巻き戻す:ROLLBACK が呼ばれたら、ログに記録した更新前の値へ1つずつ戻す
コミット前ならまだデータベース本体に書き込まれていないため、暫定値を捨てるだけで簡単に開始前へ戻せます。上のツールのSTEP5〜6で、ログをもとに暫定値が開始前の残高へ戻る様子を確認できます。
トランザクションは必ず2つの結末のどちらかで終わります。
・COMMIT(コミット):全部うまくいった → 変更をデータベース本体に書き込んで確定する
・ROLLBACK(ロールバック):何か問題が起きた → 変更を全部なかったことにして開始前に戻す
なぜ2択しかないのか。それは「中途半端な状態を決してデータベースに残さない」というルールを守るためです。コミットせずロールバックもしない、という「宙ぶらりんな状態」を許すと、他の人が読んだときに正しいデータかどうか分からなくなります。
身近な例で考えると、工事中の道路に似ています。工事が完了(コミット)すれば通れるようになり、途中で中断(ロールバック)すればコーンを全部外して元の道路に戻します。工事の途中で中途半端に片側だけ舗装して放置することはしません。
なぜロールバックが必要なのか、銀行振込の例で考えてみましょう。A口座から1000円をB口座へ送る処理の途中で障害が起きたとします。
・A口座:5000円 → 4000円(引き落とし済み)
・B口座:2000円(まだ入金されていない)
この状態でそのまま終わると、1000円がどこにも存在しないという矛盾が残ります。データベース全体の合計が6000円なのに、本来は7000円あったはずです。このような「データの帳尻が合わない状態」をデータベースは絶対に許しません。
だからロールバックでA口座を5000円に戻し、「振込はなかった」ことにするのです。やり直せる状態に戻してから、改めて正しく処理します。これがトランザクションの「全部成功か全部取り消し」という約束事(原子性)の大切さです。
ロールバックは、障害復旧(しょうがいふっきゅう=システムが止まったあと元に戻す作業)でとても重要な役割を果たします。
ロールバックが活躍する場面は次のとおりです。
・処理の途中で失敗:在庫不足や入力エラーなどで処理を続けられないとき、それまでの変更を取り消す
・システム障害からの復旧:停電などで再起動したとき、コミットされていない「中途半端なトランザクション」をログを使って巻き戻す(ロールバックリカバリ)
・デッドロックの解消:複数の処理が互いの順番待ちで動けなくなったとき、片方を取り消してやり直す
こうした巻き戻しのおかげで、トランザクションは「全部成功(コミット)」か「全部なかったことにする(ロールバック)」のどちらかになり、Aの残高だけ減ってBが増えていない、といった矛盾した状態が決して残りません。この性質を「原子性(げんしせい)」と呼びます。