PostgreSQL トランザクション
所要時間
約45分
学べること
- トランザクションの基本概念とACID特性
- 分離レベルと各レベルで発生する現象
- ロック機構と適切な使い方
- デッドロックの回避方法
- セーブポイントの活用
前提知識
- SQLの基本操作(SELECT、UPDATE等)
- テーブル設計の基礎
1. トランザクションとは
1.1 基本概念
トランザクションは、複数のデータベース操作を一つの論理的な作業単位としてまとめる仕組みです。
┌─────────────────────────────────────────────────────────┐
│ トランザクション │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ 操作 1 │ → │ 操作 2 │ → │ 操作 3 │ │
│ │ UPDATE │ │ INSERT │ │ DELETE │ │
│ └─────────┘ └─────────┘ └───────── ┘ │
│ │
│ すべて成功 → COMMIT(確定) │
│ 一つでも失敗 → ROLLBACK(取消) │
└─────────────────────────────────────────────────────────┘
1.2 基本構文
-- トランザクション開始
BEGIN;
-- 複数の操作
UPDATE accounts SET balance = balance - 1000 WHERE id = 1;
UPDATE accounts SET balance = balance + 1000 WHERE id = 2;
-- 成功したら確定
COMMIT;
-- 失敗したら取消
-- ROLLBACK;
1.3 暗黙的トランザクション
PostgreSQLでは、明示的にBEGINを書かない場合、各SQL文が自動コミットされます。
-- これらは各文が個別にコミットされる
UPDATE accounts SET balance = balance - 1000 WHERE id = 1; -- 即座にコミット
UPDATE accounts SET balance = balance + 1000 WHERE id = 2; -- 即座にコミット
-- 1つ目が成功して2つ目が失敗すると、不整合が発生する!
重要: 複数の関連する操作は必ず明示的なトランザクションで囲むこと。
2. ACID特性
トランザクションが保証する4つの特性です。
2.1 概要
┌─────────────────────────────────────────────────────────────────────┐
│ ACID特性 │
├──────────────┬──────────────────────────────────────────────────────┤
│ Atomicity │ 原子性:全部成功 or 全部失敗、中途半端な状態はない │
│ (原子性) │ │
├──────────────┼──────────────────────────────────────────────────────┤
│ Consistency │ 一貫性:制約違反があればトランザクションは失敗 │
│ (一貫性) │ │
├──────────────┼──────────────────────────────────────────────────────┤
│ Isolation │ 分離性:同時実行されるトランザクションは互いに干渉しない │
│ (分離性) │ │
├──────────────┼──────────────────────────────────────────────────────┤
│ Durability │ 永続性:コミットされたデータは永続的に保存される │
│ (永続性) │ │
└──────────────┴──────────────────────────────────────────────────────┘
2.2 原子性(Atomicity)の例
-- 銀行の 送金処理
BEGIN;
-- 送金元から引き落とし
UPDATE accounts SET balance = balance - 10000 WHERE id = 1;
-- 送金先に入金(ここでエラーが発生したと仮定)
UPDATE accounts SET balance = balance + 10000 WHERE id = 999; -- 存在しないID
-- エラーが発生すると、最初のUPDATEも取り消される
ROLLBACK; -- または自動的にロールバック
-- 結果:どちらの口座も変更されない(原子性が保証される)
2.3 一貫性(Consistency)の例
-- 制約による一貫性の保証
CREATE TABLE accounts (
id SERIAL PRIMARY KEY,
balance NUMERIC(15,2) CHECK (balance >= 0) -- 残高は0以上
);
BEGIN;
UPDATE accounts SET balance = balance - 10000 WHERE id = 1;
-- balance が負になる場合、CHECK制約違反でトランザクション全体が失敗
COMMIT;
2.4 分離性(Isolation)の詳細
分離性は次のセクションで詳しく説明します。
2.5 永続性(Durability)の保証
┌─────────────────────────────────────────────────────────┐
│ 永続性の実現方法 │
│ │
│ COMMIT実行 │
│ ↓ │
│ WAL(Write-Ahead Log)に書き込み │
│ ↓ │
│ ディスクに同期(fsync) │
│ ↓ │
│ クライアントに成功を返答 │
│ │
│ ※ サーバークラッシュ時もWALから復旧可能 │
└─────────────────────────────────────────────────────────┘
3. トランザクション 分離レベル
3.1 分離レベルの概要
PostgreSQLは4つの分離レベルをサポートしています。
┌─────────────────────────────────────────────────────────────────────────────────┐
│ トランザクション分離レベル │
├──────────────────────┬──────────────────────────────────────────────────────────┤
│ 分離レベル │ 説明 │
├──────────────────────┼──────────────────────────────────────────────────────────┤
│ READ UNCOMMITTED │ 他のコミットされていない変更が見える │
│ │ ※ PostgreSQLでは READ COMMITTED と同等 │
├──────────────────────┼──────────────────────────────────────────────────────────┤
│ READ COMMITTED │ 他のコミットされた変更のみが見える(デフォルト) │
│ │ 各SQL文の実行時点でのスナップショット │
├──────────────────────┼──────────────────────────────────────────────────────────┤
│ REPEATABLE READ │ トランザクション開始時点のスナップショットを使用 │
│ │ 同じクエリは常に同じ結果 │
├──────────────────────┼──────────────────────────────────────────────────────────┤
│ SERIALIZABLE │ 完全な直列化可能性を保証 │
│ │ 最も厳格だが、競合時にエラーになる可能性 │
└──────────────────────┴──────────────────────────────────────────────────────────┘