PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Postgresql:PREPARAZIONE DELLA TRANSAZIONE

Sì, è possibile, ma ne hai davvero bisogno?

Pensaci due volte prima di decidere che in realtà devono essere due database separati.

Potresti semplicemente mantenere aperte entrambe le connessioni e ROLLBACK il primo comando se il secondo fallisce.

Se hai davvero bisogno di transazioni preparate, continua a leggere.

Per quanto riguarda il tuo schema, userei i generatori di sequenze e la clausola RETURNING sul lato database, solo per comodità.

CREATE TABLE tbl_album (
  id    serial PRIMARY KEY,
  name  varchar(128) UNIQUE,
  ...
);
CREATE TABLE tbl_user_album (
  id          serial PRIMARY KEY,
  album_id    bigint NOT NULL,
  ...
);

Ora avrai bisogno di un po' di colla esterna - il coordinatore delle transazioni distribuite (?) - per farlo funzionare correttamente.

Il trucco è usare PREPARE TRANSACTION invece di COMMIT . Quindi, dopo che entrambe le transazioni sono riuscite, utilizza COMMIT PREPARED .

Di seguito è riportato il proof-of-concept PHP.

ATTENZIONE! a questo codice manca il critico parte - questo è il controllo degli errori. Qualsiasi errore in $db2 dovrebbe essere catturato e ROLLBACK PREPARED dovrebbe essere eseguito su $db1 Se non rilevi errori lascerai $db1 con transazioni bloccate, il che è davvero pessimo.

<?php
$db1 = pg_connect( "dbname=db1" );
$db2 = pg_connect( "dbname=db2" );
$transid = uniqid();

pg_query( $db1, 'BEGIN' );
$result = pg_query( $db1, "INSERT INTO tbl_album(name) VALUES('Absolutely Free') RETURNING id" );
$row = pg_fetch_row($result);
$albumid = $row[0];
pg_query( $db1, "PREPARE TRANSACTION '$transid'" );
if ( pg_query( $db2, "INSERT INTO tbl_user_album(album_id) VALUES($albumid)" ) ) {
    pg_query( $db1, "COMMIT PREPARED '$transid'" );
}
else {
    pg_query( $db1, "ROLLBACK PREPARED '$transid'" );
}
?>

E ancora:pensa prima di usarlo. Ciò che Erwin propone potrebbe essere più sensato.

Oh, e solo un'altra nota... Per usare questa funzione PostgreSQL, devi impostare max_prepared_transactions config variabile su un valore diverso da zero.