LASSIC Media らしくメディア

2026.10.06 らしくコラム

ロールバックとロールフォワードの違い|障害復旧の仕組み

監修・編集責任者:牛尾 昭昌(株式会社LASSIC 執行役員)

暗い机の上に置かれた複数ベイのストレージ装置と、緑色の文字が流れるターミナルを開いたノートPCが並ぶ写真。

この記事の結論

  • ロールバックはコミットされていない変更を取り消すこと、ロールフォワードはログに残った変更をやり直してデータを先へ進めることです。
  • 障害後の再起動では、ログを前へ読むロールフォワードの後に、途中だったトランザクションをロールバックして整合した状態に戻します。
  • 誤操作の前に戻すPITRもロールフォワードの応用で、ベースバックアップとアーカイブしたログがそろっていて初めて使えます。

※ 本記事は2026年10月時点の公式情報(省庁・公的機関、および製品やサービスを提供する事業者が公開している資料)に基づきます。

ロールバックとロールフォワードの違いは、トランザクションログの使い方の向きの違いです。ロールバック(取り消し)は、コミットされていない変更を元に戻します。ロールフォワード(やり直し)は、ログに記録された変更をデータファイルに改めて書き込み、データを先の時点まで進めます。停電やプロセスの異常終了の後にデータベースが自動で整合した状態に戻れるのは、この2つを組み合わせて復旧しているからです。

なお、リリースの現場で「ロールバック」と言うと、デプロイした新しい版を前の版へ切り戻すことを指す場合が多くあります。こちらはアプリケーションの配置の話で、データベースの中で変更を取り消す話とは別物です。デプロイの切り戻しの設計は「デプロイ・リリース戦略」で扱っています。本記事では、PostgreSQL、MySQL(InnoDB)、SQL Server、Oracle Databaseの公式ドキュメントをもとに、データベースの障害復旧での2つの意味を整理します。

ロールバックとロールフォワードとは

ロールバックは、トランザクションが行った変更をなかったことにする操作です。PostgreSQLのマニュアルは、SQLのROLLBACKコマンドについて、現在のトランザクションをロールバックし、そのトランザクションが行ったすべての更新を破棄すると説明しています。*1 障害で途中のまま止まったトランザクションを、データベースが再起動のときに自動で取り消す場合もあります。

ロールフォワードは、ログに記録された変更を、データファイルにもう一度当てていく操作です。PostgreSQLのマニュアルは、データページにまだ反映されていない変更をWALのレコードからやり直すことを、ロールフォワードによる復旧、別名REDOと呼んでいます。*2 WAL(Write-Ahead Logging)は、データファイルを書き換える前に変更内容をログへ書く仕組みで、詳しくは「WALとは」で解説しています。

2つは逆向きの操作ですが、どちらもトランザクションログを材料にします。全部実行されるか全く実行されないかのどちらかになる原子性と、コミットした変更を失わない耐久性を、実装の面で支えているのがこの2つです。ACIDの4つの性質そのものは「ACID特性とは」で説明しています。

仕組み:ログに残る2種類の情報

取り消しとやり直しができるのは、ログに変更前と変更後の両方の手がかりが残っているからです。SQL Serverのドキュメントは、データ変更のログレコードには、行った論理的な操作か、変更前のイメージと変更後のイメージのどちらかが記録されると説明しています。やり直すときは操作をもう一度行うか変更後のイメージを当て、取り消すときは逆の操作を行うか変更前のイメージを当てます。*3

MySQLのInnoDBは、この2つを別のログに分けています。redoログは、クラッシュリカバリで未完了のトランザクションが書いたデータを正すために使うディスク上のデータ構造で、データファイルへの反映が済まないまま止まった変更は、起動時に接続を受け付ける前に自動で再生されます。*4 undoログは、1つの読み書きトランザクションに結び付いたundoログレコードの集まりで、そのトランザクションによる最新の変更を取り消す方法を記録しています。*5

undoログの変更前のデータは、他のトランザクションが一貫性のある読み取りで元のデータを見るときにも使われます。どの版のデータが見えるかを決める規則は「トランザクション分離レベル」で扱っています。

障害復旧での2つの段階

障害後の再起動で、トランザクションログを使って行う2つの段階を示した図。上段のログでは、チェックポイントの後にコミット済みのトランザクションT1と、コミット前で止まったトランザクションT2があり、末尾で障害が起きている。段階1のロールフォワード(REDO・やり直し)では、チェックポイントから末尾まで前へ読み、データファイルに届いていない変更をT1もT2も再び書き込む。段階2のロールバック(UNDO・取り消し)では、コミットされていないT2の変更だけを後ろから順に元へ戻す。結果として、コミット済みのT1の変更だけが残り、データベースは整合した状態で開く。

障害で止まったデータベースを再起動すると、まずロールフォワード、次にロールバックの順に進みます。Oracle Databaseのドキュメントは、インスタンス・リカバリの最初の段階をキャッシュ・リカバリまたはロールフォワードと呼び、オンラインREDOログに記録されたすべての変更をデータファイルに再適用すると説明しています。この時点のデータには、障害の前にデータファイルへ書かれていた未コミットの変更も含まれうるため、続く段階でundoブロックを当ててそれらを取り消します。この段階はロールバック、またはトランザクション・リカバリと呼ばれます。*6

SQL Serverでは、復旧は3つの段階に分かれます。ログを分析して最後のチェックポイントを見つけ、ダーティページの表と実行中だったトランザクションの表を作る分析の段階、データファイルに書かれていなかった可能性のある変更をすべてロールフォワードするREDOの段階、そして未完了のトランザクションをロールバックするUNDOの段階です。*7

MySQLのInnoDBも、redoログの適用は接続を受け付ける前に行い、その後はできるだけ早く接続を受け付けます。異常終了の時点でコミットされていなかったトランザクションのロールバックは、バックグラウンドのスレッドが新しい接続の処理と並行して行います。*8 PostgreSQLのマニュアルはクラッシュ後の復旧をWALの再生として説明しており、行を更新・削除しても古い版の行をすぐには消さない作りです。*9 製品ごとに段階の名前や分け方は違いますが、ログを前へ読んで変更をやり直し、途中のものを取り消すという考え方は共通しています。

ロールバックとロールフォワードの違い

ロールバックとロールフォワードの違い(PostgreSQL・MySQL・SQL Server・Oracle Databaseの公式ドキュメントをもとにこの記事で整理)
観点 ロールバック(取り消し) ロールフォワード(やり直し)
別名 UNDO REDO
対象 コミットされていない変更 ログに記録された変更(コミット済みのものを含む)
使う情報 変更前のイメージ、undoログ、逆の操作 変更後のイメージ、redoログ・WAL、操作のやり直し
起きる場面 ROLLBACKの発行、エラー、障害後の再起動 障害後の再起動、バックアップからの復元(PITRを含む)
結果 トランザクションが始まる前の状態に戻る ログが記録している時点までデータが進む

違いの根っこは、時間をどちらへ動かすかです。ロールバックはトランザクションの開始時点へ戻し、ロールフォワードは過去の状態から記録をたどって先へ進めます。バックアップから復元して最新の状態へ近づける操作は、ロールバックではなくロールフォワードです。

具体例:SQLiteでROLLBACKを試す

アプリケーションから発行するロールバックは、手元のPythonで確かめられます。標準ライブラリのsqlite3で、振替の途中に障害が起きたことにしてロールバックする例です(Python 3.12.10、SQLite 3.49.1で実行)。

import sqlite3

con = sqlite3.connect(":memory:", autocommit=False)
con.execute("CREATE TABLE account(id INTEGER PRIMARY KEY, balance INTEGER)")
con.executemany("INSERT INTO account VALUES(?, ?)", [(1, 1000), (2, 0)])
con.commit()

try:
    con.execute("UPDATE account SET balance = balance - 300 WHERE id = 1")
    print("途中:", con.execute("SELECT * FROM account").fetchall())
    raise RuntimeError("入金側の処理で障害")
except RuntimeError as e:
    con.rollback()
    print("取り消し:", e)

print("結果:", con.execute("SELECT * FROM account").fetchall())
途中: [(1, 700), (2, 0)]
取り消し: 入金側の処理で障害
結果: [(1, 1000), (2, 0)]

UPDATEの直後には残高が700に見えていますが、rollback()を呼んだ後は1000に戻っています。Pythonのドキュメントは、rollback()を保留中のトランザクションの開始時点まで戻す操作と説明しています。autocommitをFalseにすると、コミットやロールバックの後に新しいトランザクションが暗黙に開かれます。*10 業務のコードでも、複数の更新を1つのトランザクションにまとめ、例外のときにロールバックする形にしておけば、途中までの更新は残りません。

具体例:PostgreSQLのPITR

ロールフォワードを日々の運用で意識するのは、誤ってテーブルを消した、間違った一括更新を流した、といった論理的な障害から戻す場面です。PostgreSQLの継続的アーカイブとPITR(Point-in-Time Recovery、時点を指定した復旧)では、過去に取った物理バックアップを戻し、アーカイブしたWALを目的の時刻まで再生します。*11 次の設定はマニュアルの記述をもとにした例で、手元にPostgreSQLが無いため実行していません。

# postgresql.conf に書く復旧の設定(未実行の例)
restore_command = 'cp /mnt/server/archivedir/%f %p'
recovery_target_time = '2026-09-29 17:14:00+09'
recovery_target_inclusive = off
recovery_target_action = 'pause'

# データディレクトリに空のファイルを置いてから起動する
$ touch $PGDATA/recovery.signal

recovery_target_timeは復旧をどの時刻まで進めるかを指定します。recovery_target_inclusiveは目標ちょうどの直後で止まるか(on)直前で止まるか(off)を決め、既定はonです。recovery_target_actionの既定はpauseで、目標に達すると復旧を一時停止し、望んだ時点に戻ったかを問い合わせで確かめられます。*12

MySQLでも考え方は同じです。PITRの材料は、フルバックアップの後に作られたバイナリログのファイル群で、mysqlbinlogでイベントを取り出し、時刻やログ上の位置で範囲を選んで当てます。*13 戻す手順そのものの訓練は「バックアップの復旧訓練」でまとめています。

つまずきやすい点

まず、長く開いたままのトランザクションです。SQL Serverのドキュメントは、コミットもロールバックもしないトランザクションがあると、多くの未コミットの変更を抱えたまま停止した場合に次の再起動の復旧が想定よりずっと長くかかり、ログも切り捨てられずに大きくなると説明しています。*3 大量の更新は小分けにしてコミットするのが基本です。

次に、再起動の直後の待ちです。InnoDBではロールバックが終わるまで、新しい接続が復旧中のトランザクションとロックで衝突することがあります。SQL ServerのEnterprise Editionには、REDOの段階が終わった時点で、UNDOの段階を続けながらデータベースを開く高速復旧があります。*7 「起動したのに一部の更新だけが待たされる」ときは、この段階を疑います。

PITRにも落とし穴があります。PostgreSQLでは、停止する時点はベースバックアップの終了時刻より後でなければならず、バックアップを取っている最中の時刻へは、その前のベースバックアップからロールフォワードし直す必要があります。 WALのアーカイブが途切れていれば、その先へは進めません。バックアップの世代とWALの保管期間を、戻したい期間に合わせて決めておきます。

もう一つは、言葉の取り違えです。打ち合わせで「ロールバック」と言ったとき、デプロイの切り戻しを指すのか、データベースの取り消しを指すのかを確かめます。アプリケーションの版を前に戻しても、データベースのスキーマやデータは戻りません。両方を戻す手順なのかを、作業の計画書で分けて書いておきます。

外部に委託するときに確認しておきたい点

データベースの構築や運用を外部に頼むときは、まず復旧の目標を数字で決めてもらいます。どの時点まで戻せればよいか(目標復旧時点)と、どのくらいの時間で戻せばよいか(目標復旧時間)が決まれば、WALやバイナリログのアーカイブの間隔、ベースバックアップの頻度、保管する世代の数が決まります。

次に、PITRの手順が文書になっていて、検証用の環境で実際に戻してみたことがあるかを確かめます。

三つ目は、例外のときにロールバックしているか、1回のトランザクションで大量の更新を抱えていないかを、コードレビューで見てもらうことです。最後に、リリースの計画では、アプリケーションの切り戻しとデータベースの戻し方を分けて書いてもらいます。

まとめ:復旧で確かめておきたい3つの点

ロールバックとロールフォワードの違いを実務に生かすうえで、確かめておきたい点は3つに整理できます。第一に、ロールバックはコミットされていない変更を取り消す操作、ロールフォワードはログの変更をやり直してデータを先へ進める操作で、障害後の再起動では両方がこの順に動くこと。第二に、誤操作の前に戻すPITRはロールフォワードの応用で、ベースバックアップとアーカイブしたログがそろっていなければ使えないこと。第三に、長く開いたトランザクションは復旧を遅らせるため、アプリケーション側で小分けにコミットし、例外のときはロールバックすることです。

LASSICに相談するメリット

LASSICは、元請(プライムベンダー)としてシステムの開発と保守・運用を受託しています。データベースの障害復旧では、PostgreSQLの継続的アーカイブとpgBackRest、MySQLのバイナリログとmysqlbinlog、Amazon RDSの自動バックアップと特定時点への復元といった要素を、業務の要件に合わせて組み合わせます。設計では、目標復旧時点と目標復旧時間から、WALやバイナリログのアーカイブの間隔、ベースバックアップの頻度と世代数、アプリケーション側のトランザクションの大きさを決めます。運用では、TerraformでバックアップとWALの保管先を管理し、GitHub Actionsで検証用の環境への復元を定期的に回し、PrometheusとGrafanaでアーカイブの遅れや長く開いたトランザクションを監視します。

よくある質問

コミットした後でもロールバックできますか

できません。PostgreSQLのROLLBACKが取り消すのは現在のトランザクションで、コミットが済んだ変更は対象外です。コミット済みの誤った変更を戻すには、逆の更新を流すか、PITRで誤操作の直前まで戻します。

ロールフォワードはいつ人が操作するのですか

障害後の再起動で行うロールフォワードは、データベースが自動で行います。人が操作するのは、バックアップから復元してログを目的の時点まで当てる場面で、PostgreSQLならrecovery_target_timeなどの設定とrecovery.signalのファイルを用意して起動します。

レプリケーションがあればPITRは要りませんか

レプリケーションは、誤って流した削除や更新もそのまま複製先へ伝えます。誤操作の前に戻すには、ベースバックアップとアーカイブしたログを別に保管しておく必要があります。

データベースの障害復旧の設計のご相談

元請(プライムベンダー)として、バックアップと復旧の手順の設計から、復元の検証、保守・運用までご提案します。

Remoguとリラシクなら、データベースの設計や運用に加わるITエンジニアも探せます。

Remoguは、リモート前提で全国から即戦力のITプロ人材を調達するサービスです。リラシクは、扱う求人がすべてリモートワークのITエンジニア専門転職エージェントです。どちらもLASSICが運営しています。

無料相談はこちら

出典

  1. *1 参考:The PostgreSQL Global Development Group「PostgreSQL 18 Documentation: ROLLBACK」(https://www.postgresql.org/docs/current/sql-rollback.html)。出典:Description(現在のトランザクションをロールバックし、すべての更新を破棄する)を参照(2026年10月確認)
  2. *2 参考:The PostgreSQL Global Development Group「PostgreSQL 18 Documentation: 28.3. Write-Ahead Logging (WAL)」(https://www.postgresql.org/docs/current/wal-intro.html)。出典:WALの中心となる考え方と、WALレコードからのやり直し(roll-forward recovery、別名REDO)の記述を参照(2026年10月確認)
  3. *3 参考:Microsoft「SQL Server transaction log architecture and management guide」(Microsoft Learn)(https://learn.microsoft.com/en-us/sql/relational-databases/sql-server-transaction-log-architecture-and-management-guide)。出典:ログレコードの論理操作と変更前後のイメージによるロールフォワード・ロールバック、長く実行されるトランザクションの記述を参照(2026年10月確認)
  4. *4 参考:Oracle「MySQL 8.4 Reference Manual: 17.6.5 Redo Log」(https://dev.mysql.com/doc/refman/8.4/en/innodb-redo-log.html)。出典:redoログの定義(クラッシュリカバリで使うディスク上のデータ構造・接続受付前の自動再生)を参照(2026年10月確認)
  5. *5 参考:Oracle「MySQL 8.4 Reference Manual: 17.6.6 Undo Logs」(https://dev.mysql.com/doc/refman/8.4/en/innodb-undo-logs.html)。出典:undoログの定義(最新の変更を取り消す方法・一貫性のある読み取りでの利用)を参照(2026年10月確認)
  6. *6 参考:Oracle「Oracle Database Database Concepts 19c: Oracle Database Instance」(https://docs.oracle.com/en/database/oracle/oracle-database/19/cncpt/oracle-database-instance.html)。出典:Instance Recovery Phases(ロールフォワード〔キャッシュ・リカバリ〕とロールバック〔トランザクション・リカバリ〕)を参照(2026年10月確認)
  7. *7 参考:Microsoft「Restore and recovery overview (SQL Server)」(Microsoft Learn)(https://learn.microsoft.com/en-us/sql/relational-databases/backup-restore/restore-and-recovery-overview-sql-server)。出典:復旧の3段階(Analysis・Redo・Undo)と高速復旧(Fast Recovery)の記述を参照(2026年10月確認)
  8. *8 参考:Oracle「MySQL 8.4 Reference Manual: 17.18.2 InnoDB Recovery」(https://dev.mysql.com/doc/refman/8.4/en/innodb-recovery.html)。出典:InnoDB Crash Recoveryのうち、接続受付前のredoログの適用と、バックグラウンドでのロールバックとロックの衝突の記述を参照(dev.mysql.comはこの環境からcurlで403のため、WebFetchで本文を確認)(2026年10月確認)
  9. *9 参考:The PostgreSQL Global Development Group「PostgreSQL 18 Documentation: 24.1. Routine Vacuuming」(https://www.postgresql.org/docs/current/routine-vacuuming.html)。出典:24.1.2(UPDATE・DELETEで古い版の行をすぐには消さない)を参照(2026年10月確認)
  10. *10 参考:Python Software Foundation「sqlite3 — DB-API 2.0 interface for SQLite databases」(https://docs.python.org/3/library/sqlite3.html)。出典:Connection.rollback()とautocommit属性の説明を参照(2026年10月確認)
  11. *11 参考:The PostgreSQL Global Development Group「PostgreSQL 18 Documentation: 25.3. Continuous Archiving and Point-in-Time Recovery (PITR)」(https://www.postgresql.org/docs/current/continuous-archiving.html)。出典:25.3.5(復旧の手順・restore_command・recovery.signal・停止点はベースバックアップ終了後)を参照(2026年10月確認)
  12. *12 参考:The PostgreSQL Global Development Group「PostgreSQL 18 Documentation: 19.5. Write Ahead Log」(https://www.postgresql.org/docs/current/runtime-config-wal.html)。出典:19.5.5 Recovery Target(recovery_target_time・recovery_target_inclusive・recovery_target_action)を参照(2026年10月確認)
  13. *13 参考:Oracle「MySQL 8.4 Reference Manual: 9.5.1 Point-in-Time Recovery Using Binary Log」(https://dev.mysql.com/doc/refman/8.4/en/point-in-time-recovery-binlog.html)。出典:PITRの材料となるバイナリログとmysqlbinlogの説明を参照(2026年10月確認)




View