# ch08 — トランザクション

Source: https://php-school.pages.dev/topics/db/ch08-transactions/
Site: AIと学ぶPHPの学校 (https://php-school.pages.dev)
Lesson: データベース連携
Level: L4

Reference (official): https://www.php.net/manual/ja/book.pdo.php

## 本文

# ch08 — トランザクション

## 概要

「**送金処理**」を例に考える: 口座 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()` で取り消し
- 途中で例外が出たら **全部巻き戻す** ことでデータの一貫性を守れる
- 「複数の更新を全部成功させたい」ときに使う理由を説明できる

## 所要時間

スライド 4 分 + ドリル 2 問 = **15 分**

## ドリル

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

## スライド

---
marp: true
theme: dojo
paginate: true
size: 16:9
---

<!--
LLM_CONTEXT:
  Lesson 11 / Chapter 8
  目的: トランザクションで複数の更新を「全部成功 or 全部取り消し」にできる
  扱わない: 分離レベル / デッドロック / SAVEPOINT (発展)
  読み上げ時間目安: 3 分半〜4 分
-->

# トランザクション

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 円が消える**。

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

---

## `beginTransaction` → `commit` で 1 つの塊にする

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

→ ドリルへ
