採点されません。匿名です。 間違えることは学習の一部です。読むだけでもかまいません。

トランザクション

テクノロジ系 / db (PDO / SQL / マルチDB)

トランザクション

Lesson 11 / Chapter 8

なぜ必要か: 銀行振込の例

A さんの口座から B さんの口座へ 1000 円振り込む:

  1. UPDATE A SET balance = balance - 1000
  2. UPDATE B SET balance = balance + 1000

1 だけ成功して 2 で失敗すると、A さんの 1000 円が消える

→ どちらか片方しか実行されない状態を防ぎたい。

beginTransactioncommit で 1 つの塊にする

<?php
$pdo->beginTransaction();
try {
    $pdo->exec("UPDATE A SET balance = balance - 1000");
    $pdo->exec("UPDATE B SET balance = balance + 1000");
    $pdo->commit();   // 確定
} catch (PDOException $e) {
    $pdo->rollBack(); // 取り消し
}
  • beginTransaction()commit() までが 1 トランザクション
  • 例外が出たら rollBack()全部なかったことに

commit パターン: 全部成功

<?php
$pdo->beginTransaction();
$pdo->exec("INSERT INTO users (name) VALUES ('A')");
$pdo->exec("INSERT INTO users (name) VALUES ('B')");
$pdo->commit();
  • 2 件とも確定する
  • SELECT すると 2 件追加されている

rollBack パターン: 途中で失敗

<?php
$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();
} catch (PDOException $e) {
    $pdo->rollBack();
    echo "rollback\n";
}
  • 1 件目は仮に成功するが、2 件目で PK 重複の例外
  • rollBack()1 件目も取り消される
  • SELECT すると何も追加されていない

使うべき場面

  • 複数行を同時に書き換えたい (振込・在庫減 + 注文追加など)
  • どれか失敗したら全部やめたい
  • 単発の INSERT 1 件だけならトランザクションは不要

このチャプターでできるようになること

beginTransaction()commit() で複数の更新を 1 つの塊にできる

✅ 失敗したら rollBack() で全部巻き戻せる

✅ 「途中で失敗したら一貫性が崩れる」場面で使うと判断できる

→ ドリルへ

考えてみよう

既定では正解・不正解の判定はしません。自分のペースで「答えを見る」を。採点してほしい場合だけ「採点してほしい」を押してください。

ドリル 01 — 2 件 INSERT を commit

問題

accounts テーブルに次の 2 件を 1 つのトランザクションで INSERT してから commit し、

最後に "commit" と出力し、続けて id 昇順で "{id}: {balance}" を全件出してください。

追加する 2 件:

  • id = 10, balance = 1000
  • id = 11, balance = 2000

初期データは空 (テーブルだけある状態)。

期待される出力:

commit
10: 1000
11: 2000

採点

php scripts/grade.php topics/db/ch08-transactions/drill/01-commit-success/

ヒント

  • $pdo->beginTransaction(); でトランザクション開始
  • $pdo->exec("INSERT INTO accounts (id, balance) VALUES (10, 1000)"); を 2 回
  • $pdo->commit(); で確定
  • echo "commit\n"; を出す
  • 最後に SELECT id, balance FROM accounts ORDER BY id を foreach で出力

ドリル 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/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 件なので何も出ない)