データベースにはロックのポリシーとして、分離レベルというのがある。
このレベルを高めれば、データの一貫性を維持できるが、その分ロックされる時間が増え、結果としてパフォーマンスに影響したり、一貫性を損なう処理をした場合の対応について考慮しなくてはいけなくなる。
最も分離レベルが高いのをSerializableという。これを設定すると、読み取り中にデータの変更ができない。書き込み中は読み取れないという、あらゆる矛盾を排除するようなロックがかけられる。そのかわりロックがかかっている間、処理がブロックされるのでパフォーマンスが落ちる。
ほとんどのデータベースはデフォルトでReadCommittedという分離レベルを使う。これはSerializableよりもロックが甘く、トランザクション中でもコミット済みデータの読み取りを許可する。ただし、途中で削除処理のトランザクションが完了すると、読み取り中のデータと矛盾してしまう。だから反復読み取りには矛盾が発生する可能性がある。
でも、アプリケーションの用途によっては、というかたいていの場合、ReadCommittedは安全なのだ。
例えば、月末で確定したデータを月初に帳票処理する業務アプリの場合、読み取るデータは全て確定済みなのだからそのデータに関しては変更されることがない。だから現実的には矛盾は発生しないし、そういう処理はアプリケーションで禁止してしまうことができる。
とはいえ、そう簡単に割り切れないケースもあるだろう。アプリケーション側でロックを実装する必要があるかもしれない。
並行処理が必要ないなら何にしたってかまわない。
自動的にデータを収集するシステムなどで、いつデータが入ってくるのか分からない場合はロックの少ないReadComittedを使うことでブロックしないアプリケーションが作れる。
OracleやSQLServerのような高度なデータベースはReadCommitted Snapshotなどというようなものを使えるらしい。