分離レベルの基本概念
データベーストランザクションには4つの分離レベルが存在し、整合性と並行性のバランスを調整します。レベルは低い順に次の通りです:
- Read Uncommitted(未コミット読み取り)
- Read Committed(コミット済み読み取り)
- Repeatable Read(反復可能読み取り)
- Serializable(直列化可能)
- ダーティリード: 未コミットの変更を別トランザクションが読み取る
- 非再現読み取り: 同一トランザクション内の複数回の読み取り結果が不一致
- ファントムリード: 範囲クエリで新規レコードが突然出現する現象
Read Uncommitted(未コミット読み取り)
未コミットの変更を他トランザクションが参照可能です。例:銀行口座振込処理中、送金元が$10,000減額(未コミット)の状態で、別ユーザーが残高を確認すると一時的な不一致が発生。この現象がダーティリードです。整合性保証が最も低く、実用は稀です。
Read Committed(コミット済み読み取り)
コミット済みデータのみ読み取ります。例:ECサイトの在庫管理で、商品Aの在庫数10をユーザーが確認。同時に管理者が在庫を8に更新しコミット。ユーザーが再度確認すると在庫数が変化。ダーティリードは防止できますが、非再現読み取りが発生します。SQL ServerやOracleのデフォルトレベルです。
SELECT stock_count FROM products WHERE product_id = 101 FOR UPDATE;
スナップショット機構によりロックなしで一貫性を提供しますが、更新操作との競合は解決できません。
Repeatable Read(反復可能読み取り)
トランザクション開始時のデータ状態を維持します。例:月末集計処理中、売上データの合計値を計算している間、新規売上記録の追加をブロック。これにより非再現読み取りを防止しますが、新規レコード挿入によるファントムリードは未解決です。MySQLのデフォルトレベルです。
Serializable(直列化可能)
トランザクションを完全直列処理します。例:航空券予約システムで座席確保処理を逐次実行。全ての整合性問題を解決しますが、パフォーマンス低下が顕著で実運用は限定的です。
MySQLにおけるファントムリード対策
発生条件:InnoDBストレージ・Repeatable Readレベル・現在読み取り操作時
原因:既存レコードロックでは新規挿入をブロック不可
解決手法:
- スナップショット読み取り:MVCC(多版同時実行制御)で整合性確保
- 現在読み取り:ネクストキーロック(レコード+ギャップロック)で挿入防止
-- 現在読み取りのロック例
SELECT * FROM orders WHERE user_id = 2001 LOCK IN SHARE MODE;
操作タイプ比較:
| 読み取り種別 | 取得データ | ロック方式 | 使用例 |
|---|---|---|---|
| スナップショット | トランザクション開始時点 | ロックなし | 基本SELECT |
| 現在 | 最新コミット値 | 明示的ロック | SELECT FOR UPDATE |
分離レベルと問題の対応関係
| 分離レベル | ダーティリード | 非再現読み取り | ファントムリード |
|---|---|---|---|
| Read Uncommitted | 発生 | 発生 | 発生 |
| Read Committed | 防止 | 発生 | 発生 |
| Repeatable Read | 防止 | 防止 | 発生 |
| Serializable | 防止 | 防止 | 防止 |