トランザクション
テクノロジ系 / db (PDO / SQL / マルチDB)
トランザクション
Lesson 11 / Chapter 8
なぜ必要か: 銀行振込の例
A さんの口座から B さんの口座へ 1000 円振り込む:
UPDATE A SET balance = balance - 1000UPDATE B SET balance = balance + 1000
1 だけ成功して 2 で失敗すると、A さんの 1000 円が消える。
→ どちらか片方しか実行されない状態を防ぎたい。
beginTransaction → commit で 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 = 1000id = 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 = 2000→ PK 重複 で例外発生
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 件なので何も出ない)