はじめに
こんにちは。アメリカに住みながら、独学でエンジニアを目指しているTairaです。
SQLを学習中ですが、トランザクションの中で発生してしまうダーティーリード、Non_repeatable read(反復不能読み取り), ファントムリードがあります。
本日はその中でもNon_repeatable readについて説明していきたいと思います。
Non-repeatable read(ノンリピータブルリード)とは
**Non-repeatable read(ノンリピータブルリード)**とは、データベースのトランザクション処理で起こる異常現象の一つです。
同一トランザクション内で複数回同じデータを読み取った際に、そのデータが途中で変更され、異なる結果が得られる現象です。
例えば、以下のようなケースです。
- トランザクションAが口座残高を確認すると10万円でした。
- トランザクションBが口座残高を20万円に更新し、コミットします。
- 再びトランザクションAが同じ口座残高を確認すると、20万円になってしまっています。
このように、同じトランザクションで2回の読み取り結果が異なるため「ノンリピータブル(再現不可)な読み取り」と呼ばれます。
なぜ発生するのか?
Non-repeatable readは、あるトランザクションが読み取りをした後、別のトランザクションがそのデータを更新しコミットしてしまうことが原因で発生します。これはトランザクションの分離レベルが低いために起きる問題です。
分離レベルによる影響
SQLのトランザクション分離レベルによって、Non-repeatable readが防げるかどうかが変わります。
Isolation Level | Non-repeatable read を防げるか |
---|---|
READ UNCOMMITTED | ❌ 防げない |
READ COMMITTED | ❌ 防げない |
REPEATABLE READ | ✅ 防げる |
SERIALIZABLE | ✅ 防げる |
- READ UNCOMMITTED、READ COMMITTEDでは防げません。
- REPEATABLE READ以上では、データにロックをかけたり、REPEATABLE READの場合は最初のスクリーンショットをとりそれと比較することで、この問題を防ぐことができます。
具体例(銀行口座の場合)
時間 | トランザクションA(顧客) | トランザクションB(銀行) |
---|---|---|
t1 | 口座の残高を確認 ⇒ 10万円 | |
t2 | 残高を20万円に変更し、コミット | |
t3 | 再度口座の残高を確認 ⇒ 20万円に変更 |
顧客は1回目と2回目の結果が違うため混乱します。これがNon-repeatable readの典型的な例です。
対策
Non-repeatable readを防ぐには、トランザクションの分離レベルをREPEATABLE READ以上に設定します。
MySQLでの設定例:
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
まとめ
- Non-repeatable readはトランザクション内での読み取り結果が変化する現象です。
- 分離レベルを高く設定することで防止できます。
- トランザクション処理の際は、この問題を理解して適切な設定を行いましょう。