Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【PHP8.x】Pdo\Sqlite::rollBack()メソッドの使い方

rollBackメソッドの使い方について、初心者にもわかりやすく解説します。

作成日: 更新日:

基本的な使い方

rollBackメソッドは、データベースのトランザクションをキャンセルし、トランザクション開始以降に行われた全てのデータベース操作による変更を元に戻す(ロールバックする)メソッドです。データベースにおけるトランザクションとは、複数のデータベース操作を一つのまとまりとして扱い、そのまとまりの中の全ての操作が成功した場合にのみ変更を確定させ、一つでも失敗した場合には全ての変更を取り消すことで、データの整合性を保証する仕組みです。このメソッドは、PHPのPDO(PHP Data Objects)拡張機能の一部であり、特にPdo\Sqliteクラスを含むPDOクラスのインスタンスを通じて利用できます。

通常、beginTransaction()メソッドでトランザクションを開始し、一連のデータベース操作を実行した後、何らかの理由で処理が失敗したり、途中で中断する必要が生じたりした場合にrollBack()メソッドを呼び出します。これにより、データベースはトランザクション開始前の状態に戻り、不完全なデータが保存されることを防ぎます。トランザクションが成功した場合にはcommit()メソッドで変更を確定させます。rollBack()メソッドは、予期せぬエラー発生時においてもデータの整合性を保ち、信頼性の高いデータベース操作を実現するために不可欠な機能です。

構文(syntax)

1<?php
2$pdo = new PDO('sqlite:./my_database.db');
3$pdo->rollBack();

引数(parameters)

引数なし

引数はありません

戻り値(return)

bool

トランザクションをロールバックし、データベースへの変更を元に戻した場合は true を返します。ロールバックに失敗した場合は false を返します。

サンプルコード

PHP PDO SQLite トランザクションロールバックする

1<?php
2
3/**
4 * PDO SQLite のトランザクションとロールバックのサンプル
5 *
6 * このコードは、PHP PDO を使用して SQLite データベースでトランザクションを開始し、
7 * エラー発生時にすべての変更を元に戻す (ロールバックする) 方法を示します。
8 * システムエンジニアを目指す初心者向けに、データベース操作の安全性と一貫性を保つ
9 * トランザクションの重要性を理解するための基本的な例です。
10 */
11
12// 一時的なSQLiteデータベースファイルを定義
13$dbFile = __DIR__ . '/temp_app.sqlite';
14$pdo = null; // PDOオブジェクトを初期化
15
16try {
17    // 1. SQLite データベースに接続
18    // データベースファイルが存在しない場合、PDOが自動的に作成します。
19    $pdo = new PDO('sqlite:' . $dbFile);
20
21    // PDOのエラーモードを例外に設定
22    // これにより、SQLエラーが発生した際にPDOExceptionがスローされ、
23    // catchブロックでエラーを捕捉できるようになります。
24    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
25
26    echo "データベースに接続しました。\n";
27
28    // 2. ユーザー情報を格納するテーブルが存在しない場合に作成
29    $pdo->exec('CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT NOT NULL, email TEXT UNIQUE)');
30    echo "テーブル 'users' が作成または既に存在します。\n";
31
32    // 3. トランザクションを開始
33    // ここから先に行われるデータベース操作は、一時的に保持され、
34    // commit() が呼び出されるまでデータベースに永続的に書き込まれません。
35    $pdo->beginTransaction();
36    echo "トランザクションを開始しました。\n";
37
38    // 4. ユーザーを挿入する最初の操作
39    $stmt1 = $pdo->prepare('INSERT INTO users (name, email) VALUES (?, ?)');
40    $stmt1->execute(['田中 太郎', 'tanaka.taro@example.com']);
41    echo "1人目のユーザー '田中 太郎' を挿入しました。\n";
42
43    // 5. 意図的にエラーを発生させるための操作
44    // ここでは、存在しないカラム 'invalid_column' にデータを挿入しようとすることで、
45    // SQLエラーを発生させます。
46    // このエラーにより、PDOException がスローされ、catchブロックに処理が移ります。
47    $stmt2 = $pdo->prepare('INSERT INTO users (name, invalid_column) VALUES (?, ?)');
48    $stmt2->execute(['佐藤 花子', 'sato.hanako@example.com']);
49    echo "2人目のユーザー '佐藤 花子' を挿入しました。\n"; // この行はエラーのため実行されません
50
51    // 6. すべての操作が成功した場合、変更を確定 (コミット)
52    // 上記でエラーが発生するため、この行は通常実行されません。
53    $pdo->commit();
54    echo "トランザクションがコミットされました。\n";
55
56} catch (PDOException $e) {
57    // 7. エラーが発生した場合、トランザクションをロールバック
58    // rollBack() メソッドは、beginTransaction() 以降に行われたすべての変更を破棄し、
59    // データベースをトランザクション開始前の状態に戻します。
60    if ($pdo && $pdo->inTransaction()) {
61        // トランザクションがアクティブな場合のみロールバックを実行
62        $pdo->rollBack(); // Pdo\Sqlite::rollBack を呼び出す
63        echo "エラーが発生したため、トランザクションをロールバックしました。\n";
64        echo "ロールバックにより、'田中 太郎' の挿入も取り消されます。\n";
65    }
66    echo "エラー: " . $e->getMessage() . "\n";
67
68} finally {
69    // 8. データベース接続を閉じる
70    // PDOオブジェクトをnullに設定することで、データベース接続が閉じられます。
71    $pdo = null;
72    echo "データベース接続を閉じました。\n";
73
74    // 9. クリーンアップ: 使用した一時的なデータベースファイルを削除
75    if (file_exists($dbFile)) {
76        unlink($dbFile);
77        echo "一時データベースファイル '{$dbFile}' を削除しました。\n";
78    }
79}
80
81// ロールバックが正常に行われたことを確認するために、
82// データベースファイルが存在しないことを確認できます。
83// もし存在する場合でも、テーブルを再度作成して内容を確認すれば、
84// 何もデータが挿入されていないことが分かります。
85?>

このPHPコードは、PHPのPDO拡張機能とSQLiteデータベースを使用して、トランザクションとロールバックの基本的な動作をシステムエンジニアを目指す初心者向けに解説します。まず、データベースに接続した後、beginTransaction()メソッドでトランザクションを開始します。これにより、その後の複数のデータベース操作は一時的にまとめられ、まだデータベースには永続的に書き込まれません。コード内では、最初のユーザーデータを挿入し、次に意図的にエラーを発生させるために存在しないカラムへの挿入を試みています。このエラーが発生すると、処理はcatchブロックに移り、$pdo->rollBack()メソッドが呼び出されます。rollBack()メソッドは引数を取らずに実行され、トランザクション開始からエラー発生までの間に行われたすべてのデータベース変更をキャンセルし、データベースをトランザクション開始前の状態に戻します。その結果、不完全なデータがデータベースに記録されることを防ぎ、データの整合性を確実に保つことができます。rollBack()は処理が成功した場合はブール値trueを、失敗した場合はfalseを戻り値として返します。この仕組みは、システム開発においてデータベース操作の安全性を確保するための重要な概念です。

このサンプルコードは、データベース操作の安全性と一貫性を保つrollBackの重要性を示しています。rollBackは、beginTransactionで開始したトランザクション内でエラーが発生した際、それまでのすべてのデータベース変更を元に戻し、不完全なデータが永続化されるのを防ぐために使われます。ロールバックを実行する前には、inTransaction()メソッドでトランザクションがアクティブか確認することが推奨されます。これは、トランザクションが開始されていない場合や、既にコミットまたはロールバックされている場合に不要なエラーを避けるためです。一度commit()された変更にはrollBackは影響せず、トランザクションが正常に完了した場合は呼び出す必要がありません。また、finallyブロックでのデータベース接続の解放や一時ファイルの削除といったクリーンアップ処理は、リソースリークを防ぐために確実に行うことが大切です。

PHPでマイグレーションロールバックする

1<?php
2
3// データベースファイルのパスを定義します。
4// スクリプトと同じディレクトリに 'migration_test.sqlite' というファイルが作成されます。
5$dbFile = __DIR__ . '/migration_test.sqlite';
6
7/**
8 * データベースマイグレーションの実行をシミュレートし、
9 * エラー発生時のトランザクションロールバックの挙動を示します。
10 *
11 * この関数は、データベース操作をトランザクション内で実行し、
12 * 意図的にエラーを発生させることで、変更がロールバックされる(取り消される)過程を示します。
13 *
14 * @param string $dbPath データベースファイルのパス。
15 * @return void
16 */
17function simulateMigrationRollback(string $dbPath): void
18{
19    $pdo = null; // PDOオブジェクトを初期化します。
20
21    // 以前の実行で作成された可能性のあるデータベースファイルを削除し、クリーンな状態から開始します。
22    if (file_exists($dbPath)) {
23        unlink($dbPath);
24        echo "既存のデータベースファイル '$dbPath' を削除しました。\n";
25    }
26
27    try {
28        // 1. SQLiteデータベースに接続します。
29        // 指定されたパスにファイルが存在しなければ、新しいデータベースファイルが作成されます。
30        $pdo = new PDO("sqlite:$dbPath");
31        // エラー発生時に例外をスローするようPDOを設定します。
32        $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
33        echo "データベースに接続しました: $dbPath\n";
34
35        // 2. トランザクションを開始します。
36        // beginTransaction() 以降に行われるデータベース操作は、commit() が呼び出されるか、
37        // rollBack() が呼び出されるまで、一時的なものとして扱われます。
38        $pdo->beginTransaction();
39        echo "トランザクションを開始しました。\n";
40
41        // 3. マイグレーション操作の実行をシミュレートします。
42        // 'products' テーブルが存在しない場合に作成します。
43        $pdo->exec("CREATE TABLE IF NOT EXISTS products (
44            id INTEGER PRIMARY KEY AUTOINCREMENT,
45            name TEXT NOT NULL,
46            price REAL NOT NULL
47        )");
48        echo "テーブル 'products' を作成または確認しました。\n";
49
50        // データを挿入します。これらの操作はまだ永続化されていません。
51        $stmt = $pdo->prepare("INSERT INTO products (name, price) VALUES (:name, :price)");
52        $stmt->execute([':name' => 'Laptop', ':price' => 1200.00]);
53        $stmt->execute([':name' => 'Mouse', ':price' => 25.00]);
54        echo "2つの商品を挿入しました。\n";
55
56        // **********************************************
57        // 4. ここでエラーを意図的に発生させ、トランザクションのロールバックをトリガーします。
58        // 実際のマイグレーションでは、SQL構文エラー、ユニーク制約違反、
59        // またはアプリケーションロジックでの検証失敗などがこれに該当します。
60        // **********************************************
61        echo "意図的にエラーを発生させます...\n";
62        throw new Exception("マイグレーション処理中に致命的なエラーが発生しました!");
63
64        // エラーが発生しない場合、ここに到達しコミットされます。
65        // $pdo->commit();
66        // echo "トランザクションをコミットしました。変更が永続化されました。\n";
67
68    } catch (PDOException $e) {
69        // PDO関連のエラー(例: SQLエラー)が発生した場合の処理です。
70        echo "PDOエラーが発生しました: " . $e->getMessage() . "\n";
71        if ($pdo && $pdo->inTransaction()) {
72            // トランザクションがアクティブな場合、変更をロールバック(取り消し)します。
73            // これにより、beginTransaction() 以降に行われたすべての操作が元に戻されます。
74            $pdo->rollBack(); // Pdo\Sqlite (PDO) の rollBack メソッドを呼び出す
75            echo "トランザクションをロールバックしました。すべての変更は取り消されました。\n";
76        }
77    } catch (Exception $e) {
78        // その他の一般的なPHPエラー(例: 上記で意図的にスローした例外)が発生した場合の処理です。
79        echo "一般的なエラーが発生しました: " . $e->getMessage() . "\n";
80        if ($pdo && $pdo->inTransaction()) {
81            // トランザクションがアクティブな場合、変更をロールバックします。
82            $pdo->rollBack(); // Pdo\Sqlite (PDO) の rollBack メソッドを呼び出す
83            echo "トランザクションをロールバックしました。すべての変更は取り消されました。\n";
84        }
85    } finally {
86        // データベース接続を閉じます。
87        // PDOオブジェクトはスクリプト終了時に自動的に閉じられますが、明示的にnullを設定しても問題ありません。
88        $pdo = null;
89        echo "データベース接続を閉じました。\n";
90    }
91
92    // ロールバックが成功したことを確認するために、データベースの状態をチェックします。
93    echo "\n--- データベースの状態確認 (ロールバック後) ---\n";
94    try {
95        $pdo = new PDO("sqlite:$dbPath");
96        $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
97        $stmt = $pdo->query("SELECT id, name, price FROM products");
98        $products = $stmt->fetchAll(PDO::FETCH_ASSOC);
99
100        if (empty($products)) {
101            echo "products テーブルは空です。期待通り、ロールバックが成功しました。\n";
102        } else {
103            echo "products テーブルの内容:\n";
104            foreach ($products as $product) {
105                echo "ID: " . $product['id'] . ", Name: " . $product['name'] . ", Price: " . $product['price'] . "\n";
106            }
107            echo "!!! ロールバックが失敗したか、データが残っています !!!\n";
108        }
109    } catch (PDOException $e) {
110        echo "データベース状態確認中にエラー: " . $e->getMessage() . "\n";
111    } finally {
112        $pdo = null;
113        // テスト用のデータベースファイルを削除してクリーンアップします。
114        if (file_exists($dbPath)) {
115            unlink($dbPath);
116            echo "データベースファイル '$dbPath' を削除しました。\n";
117        }
118    }
119}
120
121// 関数を実行してロールバックの挙動を確認します。
122simulateMigrationRollback($dbFile);
123

PHP 8におけるPdo\Sqlite::rollBackメソッドは、データベーストランザクション内で実行された複数の操作を、途中でエラーが発生した場合にすべて取り消し、データベースの状態をトランザクション開始前の状態に戻すための重要な機能です。このメソッドは引数を取らず、操作が成功した場合は真(true)、失敗した場合は偽(false)を返します。

データベースマイグレーションなどの一連の更新処理中に、何らかの問題が発生すると、データベースの一部だけが更新されてしまい、データの整合性が失われる可能性があります。rollBackを使用すると、beginTransactionで開始されたすべてのデータベース操作をまとめて「無かったこと」にでき、部分的な変更を防ぎます。

提供されたサンプルコードでは、SQLiteデータベースへの接続後、beginTransactionでトランザクションを開始し、テーブル作成とデータ挿入の操作をシミュレートしています。その後、意図的にエラーを発生させ、catchブロックでそのエラーを捕捉すると同時に$pdo->rollBack()を呼び出すことで、トランザクション内で実行されたテーブル作成やデータ挿入がすべて取り消され、データベースが元の状態に戻る挙動を示しています。これにより、エラー発生時でも安全にデータベースの状態を保つことができます。

このサンプルコードのrollBack()メソッドは、データベース操作中にエラーが発生した際に、beginTransaction()で開始したトランザクション内のすべての変更を安全に取り消すために使われます。初心者は、rollBack()を呼び出す前に必ずbeginTransaction()でトランザクションを開始しているか確認し、例外処理(try-catch)内でエラーを検知した場合にのみ実行することが重要です。これにより、データベースに中途半端なデータが残ることを防ぎ、整合性を保てます。inTransaction()でトランザクションがアクティブであるかを確認してからrollBack()を実行すると、より安全です。また、処理の最後にはfinallyブロックでデータベース接続を適切に閉じるようにしましょう。

関連コンテンツ