アプリケーションミューテックスとSERIALIZABLE
を使用して重要なトランザクションを保護しています。
これにより、これらの操作が可能な限り酸性になると思いますが、今では、読み取りによって、ロックが原因でこれらの書き込みトランザクションが失敗する可能性があることが懸念されます。
読み取りは、libpqxxプリペアドステートメントトランザクションにあります。 docs 、 wiki 、および ホワイトペーパー を読みましたが、読み取りトランザクションを構成して、決して実行しないようにする方法がわかりません。別の重要なシリアル化可能な書き込みトランザクションが失敗するリスクがあります。
ロックがシリアル化の失敗を引き起こすかどうかを判断できません。彼らはできますか?
アプリケーションは競合状態や古いデータなどを補正するため、読み取りは完全に酸性である必要はありません。主な懸念事項は、他の読み取りが原因でシリアル化可能な重要な書き込みトランザクションが失敗しないことです。
別のシリアル化可能なトランザクション書き込みエラーのリスクを絶対に回避するために、読み取り専用のプリペアドステートメントをどのように構成する必要がありますか?
READ ONLY
トランザクションは、明示的にLOCK TABLE
またはアドバイザリロックを使用しない限り、書き込みトランザクション(DDLを実行しない)を失敗させることはできません。
READ ONLY
トランザクションはSELECT ... FOR SHARE
またはSELECT ... FOR UPDATE
できません。彼らはDMLを実行できないため、 テーブルで取得できる最も強力なロックはACCESS SHARE
であり、これはDDLが取得するACCESS EXCLUSIVE
ロックとのみ競合します。
また、書き込みトランザクションがSERIALIZABLE
の場合、読み取り専用トランザクションによってシリアル化の失敗が発生することもありません。シリアル化の失敗では、両方のトランザクションが書き込みを実行する必要があるためです。読み取り/書き込みトランザクションの前または後に、読み取り専用トランザクションを論理的にシリアル化することは常に可能です。これらは相互に依存することができないためです。
したがって、明示的にREAD COMMITTED
を使用しない限り、READ ONLY
またはSERIALIZABLE
トランザクションをLOCK TABLE
とともに使用しても問題ありません。
また、2つのトランザクションセット間で相互作用する可能性のあるアドバイザリロックを使用しないようにする必要があります。ほとんどの場合、アドバイザリロックをまったく使用せず、これを完全に忘れることができます。
ただし、これとは別に、シリアル化の失敗やその他のトランザクションの中止に対処できるようにアプリケーションを準備する必要があります。これを回避しようとする設計はすべて壊れています。 OS /ホストマシンレベルの問題、管理アクションなどが原因でトランザクションが中止される可能性があります。「失敗できない」トランザクションに依存しないでください。どうしてもこれを行う必要がある場合は、 2フェーズコミット を使用する必要があります。ここでPREPARE TRANSACTION
(この時点で、txがコミットに失敗しないことが保証されます)、他の作業を行います。安全にコミットするtxに依存し、次にCOMMIT PREPARED
。他の作業で問題が発生した場合は、ROLLBACK PREPARED
できます。 2PCにはかなりのオーバーヘッドがあり、可能な場合は回避するのが最善ですが、選択の余地がない場合もあります。