Да, это возможно, но вам это действительно нужно?
Подумайте дважды, прежде чем решить, что это действительно должны быть две отдельные базы данных.
Вы можете просто оставить оба соединения открытыми и откатить первую команду, если вторая не удалась.
Если вам действительно нужны подготовленные транзакции, продолжайте читать.
Что касается вашей схемы - я бы использовал генераторы последовательностей и предложение RETURNING на стороне базы данных, просто для удобства.
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,
...
);
Теперь вам понадобится внешний клей — координатор распределенных транзакций (?) — чтобы все заработало правильно.
Хитрость заключается в использовании PREPARE TRANSACTION
вместо COMMIT
. Затем после успешного завершения обеих транзакций используйте COMMIT PREPARED
.
Доказательство концепции PHP приведено ниже.
ВНИМАНИЕ! в этом коде отсутствует критическая часть — контроль ошибок. Любая ошибка в $db2
должна быть обнаружена, а ROLLBACK PREPARED
должна быть выполнена в $db1
. Если вы не поймаете ошибки, вы оставите $db1
с замороженными транзакциями, что очень, очень плохо.
<?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'" );
}
?>
И еще раз - подумайте, прежде чем будете его использовать. То, что предлагает Эрвин, может быть более разумным.
Да, и еще одно замечание... Чтобы использовать эту функцию PostgreSQL, вам нужно установить max_prepared_transactions
в ненулевое значение.
person
filiprem
schedule
21.01.2012