topic: db (PDO / SQL / マルチDB) / ch08 — トランザクション / 演習 02

📝 ドリル 02 — エラーで rollBack

問題

accounts テーブルに 2 件 INSERT しようとして、2 件目で意図的に失敗 させ、 rollBack で全部巻き戻したい。最後に SELECT したとき何も追加されていないことを示す。

INSERT 内容:

  • 1 件目: id = 10, balance = 1000 → 成功するはず
  • 2 件目: id = 10, balance = 2000PK 重複 で例外発生

try ... catch (PDOException $e) で例外を捕まえて rollBack を呼び、 そのとき "rollback" と出力してください。 その後、SELECT で残った行を id 昇順で "{id}: {balance}" 形式で出す。

初期データは空。 rollBack されたので 1 件目も取り消され、SELECT は 0 件

期待される出力:

rollback

採点

php scripts/grade.php topics/11-db/ch08-transactions/drill/02-rollback-on-error/

ヒント

  • $pdo->beginTransaction(); で開始
  • try { ... $pdo->commit(); } catch (PDOException $e) { $pdo->rollBack(); echo "rollback\n"; }
  • 2 件目の INSERT で同じ id = 10 を入れれば PK 重複で例外
  • catch を抜けた後に SELECT で残りを foreach 出力 (0 件なので何も出ない)

テストケース

期待される出力

rollback

📄 starter.php(雛形)

このコードから書き始めてください。

<?php

$pdo = new PDO('sqlite:' . getenv('DOJO_DB_PATH'));
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

// TODO: beginTransaction でトランザクションを開始する

// TODO: try で 2 回 INSERT する (2 回目は id=10 を重複させて例外を起こす)
//       成功したら commit、失敗したら catch で rollBack + "rollback" を出力する

// TODO: SELECT で残った行を id 昇順で "{id}: {balance}" で出力する (0 件のはず)
✅ 解答例を見る(自分で解いてから)
<?php

$pdo = new PDO('sqlite:' . getenv('DOJO_DB_PATH'));
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$pdo->beginTransaction();
try {
    $pdo->exec("INSERT INTO accounts (id, balance) VALUES (10, 1000)");
    $pdo->exec("INSERT INTO accounts (id, balance) VALUES (10, 2000)"); // PK 重複でエラー
    $pdo->commit();
    echo "commit\n";
} catch (PDOException $e) {
    $pdo->rollBack();
    echo "rollback\n";
}

foreach ($pdo->query("SELECT id, balance FROM accounts ORDER BY id") as $row) {
    echo "{$row['id']}: {$row['balance']}\n";
}