ch08 12章中 8章目

ch08 — トランザクション

スライドで見る

この章を AI と学ぶ

💬 AI に聞く質問例 3 件
  1. 「ch08 — トランザクション」のつまずきやすいポイントを、初学者向けに3つ教えてください

    ChatGPT Claude Gemini

  2. 「ch08 — トランザクション」について、自分の手で試せる練習問題を3つ出してください (難易度を上げながら)

    ChatGPT Claude Gemini

  3. 「ch08 — トランザクション」を学んだ後、次に学ぶと良いトピックは何ですか?理由も教えてください

    ChatGPT Claude Gemini

概要

送金処理」を例に考える: 口座 A から 1000 円引いて、口座 B に 1000 円足す。これは 2 つの UPDATE で実現するが、1 つ目だけ成功して 2 つ目で失敗したら 1000 円が消える。「全部成功するか・全部失敗するか」を DB に宣言できる仕組みが トランザクション だ。

PHP では $pdo->beginTransaction() で「ここから先は一塊」と宣言し、すべて問題なければ $pdo->commit() で確定、途中で例外が出たら $pdo->rollBack()すべて巻き戻すtry { begin → SQL → commit } catch { rollBack → throw } のテンプレが定石で、exception トピックで学んだ例外処理と完全にセットで使う。

保証される性質は ACID で、特に重要なのが A (Atomicity) = 「全部か無か」の原子性。送金・複数テーブル一括 INSERT・複数行 UPDATE のように 論理的に 1 つの操作 をやるときは必ずトランザクションで括る。逆に SELECT だけや単一行更新ならトランザクション不要 (DB が 1 文単位で原子的に処理する)。

学習目標

  • beginTransaction() で「ここから先は一塊」と宣言できる
  • commit() で確定、rollBack() で取り消し
  • 途中で例外が出たら 全部巻き戻す ことでデータの一貫性を守れる
  • 「複数の更新を全部成功させたい」ときに使う理由を説明できる

ドリル

no 内容
01 2 件 INSERT を 1 トランザクションで実行 → commit → SELECT 確認
02 1 件目成功 → 2 件目で例外 → rollBack → 何も追加されていない

解説スライド 全 7 枚

右の ボタン キー(またはスワイプ)で次のスライドに進めます。 下の「縦表示」を開くと全スライドを一気に読めます。

  1. トランザクション

    Lesson 11 / Chapter 8

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

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

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

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

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

  3. 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()全部なかったことに
  4. 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 件追加されている
  5. 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 すると何も追加されていない
  6. 使うべき場面

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

    beginTransaction()commit() で複数の更新を 1 つの塊にできる ✅ 失敗したら rollBack() で全部巻き戻せる ✅ 「途中で失敗したら一貫性が崩れる」場面で使うと判断できる

    → ドリルへ

1 / 7
📜 スライドを全部一気に読む(縦表示)

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() で全部巻き戻せる ✅ 「途中で失敗したら一貫性が崩れる」場面で使うと判断できる

→ ドリルへ

この章で取り組む 演習問題の流れ (2ステップ)
  1. 01 ドリル 01 — 2 件 INSERT を commit README.md starter.php answer.php
  2. 02 ドリル 02 — エラーで rollBack README.md starter.php answer.php

演習問題の詳細

この章の演習問題の内容を読めます。実際に手元で解くには教材リポジトリを clone してください。

ドリル 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

ヒント

  • $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 で出力

🧪 ブラウザで試す

スライドのコードを写経して ▶ 実行、自分で書いて 📝 採点 で答え合わせ。初回のみ PHP ランタイム読込で数秒かかります。

PHP ランタイム未読込

          

        

ドリル 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

ヒント

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

🧪 ブラウザで試す

スライドのコードを写経して ▶ 実行、自分で書いて 📝 採点 で答え合わせ。初回のみ PHP ランタイム読込で数秒かかります。

PHP ランタイム未読込

          

        

演習問題(2問)

  1. ドリル 01 — 2 件 INSERT を commit

    README.md starter.php answer.php

  2. ドリル 02 — エラーで rollBack

    README.md starter.php answer.php

サイト内で問題文・雛形・解答例を確認できます。実際に手元で解くには教材リポジトリを clone してください。

完了にすると進捗に反映されます