トランザクション

ACID、分離レベル、ロック

ACID特性

A - Atomicity(原子性)

トランザクションは全て成功するか、全て失敗するか。中間状態なし。 ロールバックで元の状態に戻る。

C - Consistency(一貫性)

トランザクション前後でデータの整合性が保たれる。 制約違反があればロールバック。

I - Isolation(独立性)

並行トランザクションが互いに干渉しない。 分離レベルで制御。

D - Durability(永続性)

コミット後のデータは永続化され、障害があっても失われない。 WALで保証。

トランザクション分離レベル

分離レベルDirty ReadNon-RepeatablePhantom
READ UNCOMMITTED発生発生発生
READ COMMITTED防止発生発生
REPEATABLE READ防止防止発生*
SERIALIZABLE防止防止防止
Dirty Read

未コミットのデータを読んでしまう

Non-Repeatable Read

同じクエリで異なる結果が返る(他が更新)

Phantom Read

同じ条件で行数が変わる(他が挿入/削除)

*PostgreSQL: REPEATABLE READでもPhantomを防止(スナップショット分離)
*MySQL InnoDB: REPEATABLE READがデフォルト、ギャップロックでPhantomを軽減

ロック

共有ロック(S Lock)

読み取り用。複数トランザクションが同時に取得可能。 書き込みはブロック。

排他ロック(X Lock)

書き込み用。他のすべてのロックをブロック。 1つのトランザクションのみ取得可能。

行ロック

特定の行のみロック。並行性が高い(InnoDB, PostgreSQL)

テーブルロック

テーブル全体をロック。DDL操作時など

ギャップロック(MySQL)

インデックスレコード間の隙間をロック。Phantom防止

デッドロック

複数のトランザクションが互いのロック解放を待つ状態。 DBMSが検出し、一方をロールバックして解消。

デッドロックの例

TX1

1. LOCK row A

2. LOCK row B ← 待機

TX2

1. LOCK row B

2. LOCK row A ← 待機

デッドロック対策

  • • ロック取得順序を統一(ID昇順など)
  • • トランザクションを短く保つ
  • • 適切なインデックスでロック範囲を限定
  • • リトライロジックの実装

実践的なSQL

1-- トランザクション基本
2BEGIN;
3UPDATE accounts SET balance = balance - 100 WHERE id = 1;
4UPDATE accounts SET balance = balance + 100 WHERE id = 2;
5COMMIT; -- または ROLLBACK;
6
7-- 分離レベル設定
8SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
9SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
10
11-- 明示的ロック(PostgreSQL)
12SELECT * FROM orders WHERE id = 1 FOR UPDATE; -- 排他ロック
13SELECT * FROM orders WHERE id = 1 FOR SHARE; -- 共有ロック
14SELECT * FROM orders WHERE id = 1 FOR UPDATE NOWAIT; -- ロック待ちしない
15SELECT * FROM orders WHERE id = 1 FOR UPDATE SKIP LOCKED; -- ロック中はスキップ
16
17-- デッドロック確認(PostgreSQL)
18SELECT * FROM pg_stat_activity WHERE wait_event_type = 'Lock';
19
20-- デッドロック確認(MySQL)
21SHOW ENGINE INNODB STATUS;

SRE/インフラ観点

分離レベルの選択

  • • 多くのケースは READ COMMITTED で十分
  • • 金融系など厳密性が必要なら SERIALIZABLE
  • • 性能とのトレードオフを考慮

監視項目

  • • ロック待ち時間、ロック競合
  • • デッドロック発生頻度
  • • 長時間実行トランザクション
  • • アクティブトランザクション数