PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Postgresql :PRÉPARER LA TRANSACTION

Oui, c'est possible, mais en avez-vous vraiment besoin ?

Réfléchissez-y à deux fois avant de décider qu'il doit s'agir de deux bases de données distinctes.

Vous pouvez simplement garder les deux connexions ouvertes et ROLLBACK la première commande si la seconde échoue.

Si vous avez vraiment besoin de transactions préparées, continuez à lire.

Concernant votre schéma - j'utiliserais des générateurs de séquence et la clause RETURNING côté base de données, juste pour plus de commodité.

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,
  ...
);

Maintenant, vous aurez besoin d'un peu de colle externe - un coordinateur de transactions distribuées (?) - pour que cela fonctionne correctement.

L'astuce consiste à utiliser PREPARE TRANSACTION au lieu de COMMIT . Ensuite, une fois les deux transactions réussies, utilisez COMMIT PREPARED .

La preuve de concept PHP est ci-dessous.

ATTENTION ! ce code manque le critique partie - qui est le contrôle d'erreur. Toute erreur dans $db2 doit être intercepté et ROLLBACK PREPARED doit être exécuté sur $db1 Si vous n'attrapez pas d'erreurs, vous laisserez $db1 avec des transactions gelées, ce qui est vraiment, vraiment mauvais.

<?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'" );
}
?>

Et encore une fois - réfléchissez avant de l'utiliser. Ce que propose Erwin pourrait être plus sensé.

Oh et juste une note de plus... Pour utiliser cette fonctionnalité PostgreSQL, vous devez définir max_prepared_transactions variable de configuration à une valeur non nulle.