Sim, é possível, mas você realmente precisa disso?
Pense duas vezes antes de decidir que realmente devem ser dois bancos de dados separados.
Você pode apenas manter as duas conexões abertas e ROLLBACK o primeiro comando se o segundo falhar.
Se você realmente precisa de transações preparadas, continue lendo.
Em relação ao seu esquema - eu usaria geradores de sequência e cláusula RETURNING no lado do banco de dados, apenas por conveniência.
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,
...
);
Agora você precisará de alguma cola externa - coordenador de transações distribuídas (?) - para fazer isso funcionar corretamente.
O truque é usar
PREPARE TRANSACTION
em vez de COMMIT
. Depois que ambas as transações forem bem-sucedidas, use COMMIT PREPARED
. A prova de conceito do PHP está abaixo.
AVISO! este código não tem o crítico parte - que é o controle de erros. Qualquer erro em
$db2
deve ser capturado e ROLLBACK PREPARED
deve ser executado em $db1
Se você não pegar erros, você deixará $db1
com transações congeladas, o que é muito, muito ruim. <?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 novamente - pense antes de usá-lo. O que Erwin propõe pode ser mais sensato.
Ah, e só mais uma observação... Para usar esse recurso do PostgreSQL, você precisa definir
max_prepared_transactions
config variável para valor diferente de zero.