他のバージョンの文書9.6 | 9.5 | 9.4 | 9.3 | 9.2 | 9.1 | 9.0 | 8.4 | 8.3 | 8.2 | 8.1 | 8.0 | 7.4 | 7.3 | 7.2

9.4. アプリケーションレベルでのデータの一貫性チェック

PostgreSQLでのデータ読みとりはデータをロックしないので、トランザクションの隔離レベルに関係なく、あるトランザクションで読み込まれたデータは、同時に実行されているもう一方のトランザクションによって書き変えられる可能性があります。 言い換えると、SELECT で得た行は、その行が返ってきたとき (現在の問い合わせが開始されたあとのある時点) に最新であるということを意味していません。 このトランザクションが開始した後であっても別のトランザクションがコミットしたことで、見ている行は更新、もしくは削除されてしまっている可能性があります。「今」その行が有効であったとしても、現在実行中のトランザクションがコミットまたはロールバックで完了する前に(別のトランザクションによって)変更されたり、削除される可能性があります。

各々のトランザクションは特定のデータベースの内容のスナップショットを参照していて、同時に実行されているトランザクションが異なったスナップショットを参照している可能性が十分にありうると考えることもできます。したがって、どちらにしても「今」という概念は少々疑わしいものとなります。これは通常、それぞれのクライアントアプリケーションがお互いに隔離されている場合は大きな問題ではありませんが、クライアントどうしがデータベースの外で何かのチャンネルを使用して通信できる場合は大きな問題となります。

現在有効な行を確実なものとし、同時に起こりうる更新を避けるためには、SELECT FOR UPDATE 文や、適切な LOCK TABLE 文を使用する必要があります (SELECT FOR UPDATE 文は返ってきたデータのみを同時に起こる更新からロックし、LOCK TABLE はテーブル全体をロックします)。これはPostgreSQLに他の環境からアプリケーションを移植するときに考慮されなければなりません。

Note: PostgreSQL バージョン 6.5 以前のものでは、読み込みロックを使用しているので、PostgreSQL のバージョン 6.5 以前のものからバージョンアップする際には上記の対象となります。

MVCC においてはグローバル有効性チェックに特別な考慮を払わなければなりません。 たとえば銀行のアプリケーションで、テーブルにあるすべての貸方の合計が、別のテーブルにある借方の合計と同じであることをチェックする必要があるとします。そして、この両方のテーブルは常に更新されています。 2 つの連続する SELECT SUM(...) コマンドの結果を比べると、2 番目の問い合わせは、おそらく最初の問い合わせによってカウントされなかったトランザクションの結果を含んでいるため、リードコミッティドモードでは信頼のおける処理を実行できないことが分かります。 1 つのシリアライザブルトランザクションで 2 つの合計を出力すると、シリアライザブルトランザクションが開始される前にコミットされたトランザクション結果の正確な状況を得ることができます。しかし、その結果がもたらされた時点でもなお妥当であるかどうかは、実際には疑わしいかもしれません。 整合性チェックを行なう前にシリアライザブルトランザクション自身が変更を行なった場合、そのチェックの有効性はさらに疑わしくなります。これにより、トランザクション開始後に行なわれる変更のすべてではなく、その一部だけが含まれるためです。 このような場合、注意深い人であれば、現状を確実に把握するためにチェックに必要なすべてのテーブルをロックするでしょう。 SHARE モード (もしくはそれ以上) のロックにより、現在のトランザクションでの変更を除き、ロックされたテーブルにコミットされていない変更が存在しないことが保証されます。

また、明示的なロックを使用して、同時に変更が実行されるのを防ごうとする場合、リードコミッティドモードを使用すべきであることに注意してください。 もしくは、シリアライザブルモードを使用する場合は、問い合わせを実行する前にロックを獲得するよう留意してください。 シリアライザブルトランザクションにおいて獲得された明示的なロックは、テーブルに変更をかける他のトランザクションが現在実行されていないことを保証します。しかし、トランザクションが参照しているスナップショットが、ロックの獲得より前に取得されたものであれば、そのスナップショットは現時点においてコミットされている変更より前のテーブルのものである可能性があります。 シリアライザブルトランザクションのスナップショットは、実際にはその最初の問い合わせ (SELECTINSERTUPDATE、または DELETE) が開始された時点で取得されます。したがって、スナップショットを取得する前に、明示的なロックを獲得することは可能です。