PostgreSQL:准备交易

May*_*ank 2 php postgresql transactions distributed-transactions prepared-statement

我有两个数据库服务器db1和db2。

db1有一个名为tbl_album
db2的表tbl_user_album

CREATE TABLE tbl_album
(
id    PRIMARY KEY,
name  varchar(128)
...
);

CREATE TABLE tbl_user_album
(
id          PRIMARY KEY,
album_id    bigint
...
);
Run Code Online (Sandbox Code Playgroud)

现在,如果用户想创建一个相册,我的PHP代码需要做的是:

  • 在db1中创建一条记录并保存其ID(主键)
  • 使用保存在第一条语句中的记录在db2中创建记录

是否可以将这两个语句保留在事务中?我也可以使用php解决方案。我的意思是,如果有需要php代码来保留db句柄并在这些句柄上进行提交或回滚的解决方案,我就很好。

任何帮助深表感谢。

fil*_*rem 5

是的,有可能,但是您真的需要吗?

在确定这实际上必须是两个独立的数据库之前,请三思而后行。

您可以只保持两个连接都打开,如果第二个命令失败,则回滚第一个命令。

如果您确实需要准备交易,请继续阅读。

关于您的模式-为了方便起见,我将在数据库端使用序列生成器和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,
  ...
);
Run Code Online (Sandbox Code Playgroud)

现在,您将需要一些外部粘合剂-分布式事务处理协调器(?)-才能使其正常工作。

诀窍是使用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'" );
}
?>
Run Code Online (Sandbox Code Playgroud)

再说一遍-在使用前先考虑一下。欧文的建议可能更明智。

哦,还有一点需要注意...要使用此PostgreSQL功能,您需要将max_prepared_transactionsconfig变量设置为非零值。