トランザクションとACID
トランザクションとは
トランザクション? 複数のDB操作をひとまとまりとして扱う仕組み。途中でエラーが起きたら全部元に戻す(ロールバック)ことで、データの整合性を保つ。 とは、複数のSQL操作をひとまとまりの処理として扱う仕組みです。「全部成功するか、全部なかったことにするか」を保証します。
典型的な例として銀行振込を考えましょう。
-- A の口座から B の口座へ 10,000円 振込
UPDATE accounts SET balance = balance - 10000 WHERE id = 'A';
UPDATE accounts SET balance = balance + 10000 WHERE id = 'B';
1行目が成功して2行目が失敗した場合、Aの残高だけが減って消えてしまいます。トランザクションを使えば、どちらかが失敗したとき両方を取り消すことができます。
BEGIN / COMMIT / ROLLBACK
-- トランザクションの基本構文
BEGIN; -- または START TRANSACTION;
UPDATE accounts SET balance = balance - 10000 WHERE id = 'A';
UPDATE accounts SET balance = balance + 10000 WHERE id = 'B';
COMMIT; -- 全操作を確定する
-- または
ROLLBACK; -- 全操作をなかったことにする
アプリケーション側での典型的な処理フロー:
BEGIN;
-- 操作1
UPDATE accounts SET balance = balance - 10000 WHERE id = 'A';
-- 操作2
UPDATE accounts SET balance = balance + 10000 WHERE id = 'B';
-- 問題なければコミット
COMMIT;
-- エラーが発生した場合
-- ROLLBACK;
SAVEPOINT
トランザクション内に「セーブポイント」を設け、部分的なロールバックが可能です。
BEGIN;
INSERT INTO orders VALUES (...);
SAVEPOINT after_order; -- セーブポイントを設定
INSERT INTO order_items VALUES (...);
-- order_itemsだけを取り消したい場合
ROLLBACK TO after_order; -- セーブポイントまで戻る
COMMIT; -- ordersのINSERTだけ確定
ACID特性
ACID特性? トランザクションが満たすべき4つの性質。Atomicity(原子性・全部成功か全部失敗)・Consistency(一貫性)・Isolation(分離性・他のトランザクションの影響を受けない)・Durability(永続性)。 とは、トランザクションが保証する4つの特性の頭文字です。
A: Atomicity(原子性)
トランザクション内のすべての操作は「全部成功」か「全部失敗」のどちらかになります。途中の状態はありません。
C: Consistency(一貫性)
トランザクションの前後でデータベースは整合性のある状態を保ちます。外部キー制約、NOT NULL制約などがすべて満たされた状態でしかCOMMITできません。
I: Isolation(独立性)
同時に複数のトランザクションが実行されても、互いの中途状態が見えないようにします(どの程度遮断するかは分離レベルで設定します)。
D: Durability(永続性)
COMMITしたデータはハードウェア障害が起きても失われません。ディスクへの書き込みやWAL(Write-Ahead Log)によって保証されます。
分離レベルと発生する問題
複数のトランザクションが同時に実行されると、分離が不十分な場合に以下の問題が発生します。
ダーティーリード
まだコミットされていない別トランザクションの変更が見えてしまう。
T1: UPDATE accounts SET balance = 50000 WHERE id = 'A';
T2: SELECT balance FROM accounts WHERE id = 'A'; -- 50000が見える(まだT1はCOMMITしていない)
T1: ROLLBACK; -- T2が見たデータは存在しなかったことになる
ノンリピータブルリード
同一トランザクション内で同じ行を2回読んだとき、別トランザクションのCOMMITにより値が変わる。
T1: SELECT balance FROM accounts WHERE id = 'A'; -- 100000
T2: UPDATE accounts SET balance = 80000 WHERE id = 'A'; COMMIT;
T1: SELECT balance FROM accounts WHERE id = 'A'; -- 80000(変わった!)
ファントムリード
同一トランザクション内で同じ条件で検索したとき、別トランザクションのINSERT/DELETEにより行数が変わる。
T1: SELECT COUNT(*) FROM orders WHERE date = '2025-01-01'; -- 10件
T2: INSERT INTO orders (...) VALUES (...); COMMIT; -- 同じ日付で追加
T1: SELECT COUNT(*) FROM orders WHERE date = '2025-01-01'; -- 11件(幽霊行が出現)
4段階の分離レベル
分離レベル? トランザクション同士がどの程度互いの変更を見えるようにするかの設定。READ UNCOMMITTED・READ COMMITTED・REPEATABLE READ(MySQLデフォルト)・SERIALIZABLE の4段階がある。 によって、どの問題を防ぐかが決まります。
| 分離レベル | ダーティーリード | ノンリピータブル | ファントムリード |
|---|---|---|---|
| READ UNCOMMITTED | 発生 | 発生 | 発生 |
| READ COMMITTED | 防止 | 発生 | 発生 |
| REPEATABLE READ | 防止 | 防止 | 発生 |
| SERIALIZABLE | 防止 | 防止 | 防止 |
-- 分離レベルの設定(MySQL)
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-- 分離レベルの設定(PostgreSQL)
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
MySQLのInnoDBはデフォルトが REPEATABLE READ で、ネクストキーロックによりファントムリードも多くの場合防止されます。多くのアプリケーションではこのデフォルトで十分です。
デッドロック
2つのトランザクションが互いに相手のロックを待ち続ける状態をデッドロックと言います。
T1: accounts の id=A をロック
T2: accounts の id=B をロック
T1: id=B をロックしようとする → T2 が解放するまで待機
T2: id=A をロックしようとする → T1 が解放するまで待機
→ 互いに待ち続けてデッドロック
DBMSはデッドロックを検出すると、一方のトランザクションを強制ロールバックします。アプリケーション側はデッドロックエラーを受け取ったらリトライする実装が必要です。
デッドロックの回避策
-- 対策1: 常に同じ順番でテーブル・行をロックする
-- 悪い例:
-- T1: id=A → id=B の順でロック
-- T2: id=B → id=A の順でロック ← 順序が逆でデッドロック発生
-- 良い例:
-- T1: id=A → id=B の順でロック
-- T2: id=A → id=B の順でロック ← 常に同じ順序
-- 対策2: SELECT ... FOR UPDATE で先にロックを取得
BEGIN;
SELECT * FROM accounts WHERE id IN ('A', 'B') ORDER BY id FOR UPDATE;
-- ORDER BY id で常に同じ順序でロック
UPDATE accounts SET balance = balance - 10000 WHERE id = 'A';
UPDATE accounts SET balance = balance + 10000 WHERE id = 'B';
COMMIT;
-- 対策3: トランザクションを短くする(ロック保持時間を最小化)
まとめ
- トランザクションは複数の操作を「全部成功か全部失敗」にまとめる仕組み
- BEGIN / COMMIT / ROLLBACK でトランザクションを制御する
- ACID: 原子性・一貫性・独立性・永続性の4特性
- 分離不足でダーティーリード・ノンリピータブルリード・ファントムリードが発生
- 分離レベルは高いほど安全だが同時実行性能が下がる
- デッドロックはロック順序の統一とトランザクションを短くすることで回避
次回はこのシリーズ最終回として インデックス? テーブルの検索を高速化するためのデータ構造。本の索引のように、特定の列の値から行の位置をすばやく特定できる。検索は速くなるが、書き込みはやや遅くなる。 と実行計画の基礎を解説します。