Jag tror att du har missförstått PREPARE TRANSACTION
.
Det uttalandet avslutar arbetet med transaktionen, det vill säga det ska utfärdas efter allt arbete är gjort. Tanken är att PREPARE TRANSACTION
gör allt som potentiellt skulle kunna misslyckas under en commit förutom själva commit. Det är för att garantera att en efterföljande COMMIT PREPARED
kan inte misslyckas.
Tanken är att bearbetningen är som följer:
-
Kör
START TRANSACTION
på alla databaser som är involverade i den distribuerade transaktionen. -
Gör allt arbete. Om det finns fel,
ROLLBACK
alla transaktioner. -
Kör
PREPARE TRANSACTION
på alla databaser. Om det misslyckas någonstans, körROLLBACK PREPARED
på de databaser där transaktionen redan var förberedd ochROLLBACK
på de andra. -
En gång
PREPARE TRANSACTION
har lyckats överallt, körCOMMIT PREPARED
på alla inblandade databaser.
På så sätt kan du garantera "allt eller inget" över flera databaser.
En viktig komponent här som jag inte har nämnt är den distributerade transaktionshanteraren . Det är en mjukvara som ständigt memorerar var i ovanstående algoritm bearbetningen för närvarande är så att den kan städa upp eller fortsätta att utföra efter en krasch.
Utan en distribuerad transaktionshanterare är tvåfas commit inte värt mycket, och det är faktiskt farligt:om transaktioner fastnar i den "förberedda" fasen men inte är commiterade ännu, kommer de att fortsätta att hålla lås och (i fallet med PostgreSQL) blockerar autovakuumarbete även genom omstarter av servern , eftersom sådana transaktioner måste vara beständiga.
Detta är svårt att få rätt.