web-dev-qa-db-ja.com

他の書き込みシリアル化トランザクションが失敗しないように読み取りトランザクションを構成する方法

アプリケーションミューテックスとSERIALIZABLEを使用して重要なトランザクションを保護しています。

これにより、これらの操作が可能な限り酸性になると思いますが、今では、読み取りによって、ロックが原因でこれらの書き込みトランザクションが失敗する可能性があることが懸念されます。

読み取りは、libpqxxプリペアドステートメントトランザクションにあります。 docswiki 、および ホワイトペーパー を読みましたが、読み取りトランザクションを構成して、決して実行しないようにする方法がわかりません。別の重要なシリアル化可能な書き込みトランザクションが失敗するリスクがあります。

ロックがシリアル化の失敗を引き起こすかどうかを判断できません。彼らはできますか?

アプリケーションは競合状態や古いデータなどを補正するため、読み取りは完全に酸性である必要はありません。主な懸念事項は、他の読み取りが原因でシリアル化可能な重要な書き込みトランザクションが失敗しないことです。

別のシリアル化可能なトランザクション書き込みエラーのリスクを絶対に回避するために、読み取り専用のプリペアドステートメントをどのように構成する必要がありますか?

1
user32234

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にはかなりのオーバーヘッドがあり、可能な場合は回避するのが最善ですが、選択の余地がない場合もあります。

0
Craig Ringer