如何使PREPARE TRANSACTION工作

时间:2011-11-16 04:42:44

标签: sql postgresql transactions

根据Postgres文档 - 一旦准备好,稍后可以使用COMMIT PREPARED或ROLLBACK PREPARED提交或回滚事务。这些命令可以从任何会话not only the one that executed the original transaction.

发出

我正在尝试将数据从csv导入到数据库表中,为此,我正在使用

COPY tablename [ ( column [, ...] ) ] FROM { 'filename' }

所有这些都是在shell脚本中完成的。 现在的问题是我正在执行psql命令并通过-c选项将此命令作为参数传递(我通过命令启动事务

该命令中的

prepare transaction 'some-id')。

我想创建一个Savepoint并回滚它,不会出现任何错误。

在shell脚本中执行了一些其他任务之后,我检查以前的psql语句产生的错误,然后我尝试使用命令回滚

Prepared Rollback 'transaction-id'(在单独的psql command with sql statements中)

报告“No "transaction-id" found

我是否认为这个概念错了或遗漏了某些东西?

这是否发生是因为我多次发出psql命令并且每次都导致新的交易?

2 个答案:

答案 0 :(得分:8)

为了准备工作,COPYPREPARE必须在同一会话中。由于你的问题缺乏具体的命令,我假设你写的时候:

  

Prepared Rollback'transaction-id'(在带有sql语句的单独psql命令中)

您正在使用不同的psql命令来COPY和PREPARE。这是错的。将COPY和PREPARE组合到同一个会话中。

E.g。

$ psql -c "BEGIN; COPY tablename FROM '/tmp/sql'; PREPARE TRANSACTION 'foobar';" db
$ while /bin/not-ready-to-commit ; do sleep 1 ; done
$ psql -c "COMMIT PREPARED 'foobar';" db

PREPARE TRANSACTION通过将当前事务写入光盘并退出当前会话中的事务处理来工作。这就是您需要BEGIN的原因:它启动您要准备的事务。您希望受prepeare影响的所有命令必须在事务启动后(在您的情况下为COPY命令)。发出PREPARE TRANSACTION后,您当前所在的事务将使用您提供的标识符写入磁盘。准备交易后发布的任何声明不再是交易的一部分。因此,BEGIN; PREPARE... ; COPY在没有事务的情况下运行COPY操作。

这是psql shell中的一个例子:

demo=# DELETE FROM foo;
DELETE 4
demo=# BEGIN; -- start a transaction
BEGIN
DEMO=# COPY foo FROM '/tmp/sql'; -- do what you want to commit later
COPY 4
demo=# PREPARE TRANSACTION 'demo'; -- prepare the transaction
PREPARE TRANSACTION
demo=# ROLLBACK; -- this is just to show that there is no longer a transaction
NOTICE:  there is no transaction in progress
ROLLBACK
demo=# SELECT * FROM foo; -- the table is empty, copy waiting for commit
 a | b 
---+---
(0 rows)
demo=# COMMIT PREPARED 'demo'; -- do the commit
COMMIT PREPARED
demo=# SELECT * FROM foo; -- data is visible
 a | b 
---+---
 1 | 2
 3 | 4
 5 | 6
 7 | 8
(4 rows)

编辑:您必须在postgresql.conf中启用准备好的事务:

max_prepared_transactions = 1 # or more, zero (default) disables this feature.

如果max_prepared_transactions为零,则psql报告未找到事务ID,但不会警告您禁用此功能。 Psql给出了PREPARE TRANSACTION的警告,但如果你的shell脚本在prepare语句之后打印出来,很容易被错过。

答案 1 :(得分:3)

PREPARE TRANSACTION用于多个服务器上的分布式事务,通常由事务监视器或类似的应用程序服务器(例如EJB)使用。

只需将您的副本包装在常规交易块中:

START TRANSACTION;
COPY ....;
COMMIT;

如果您想在中间使用保存点,请使用SAVEPOINT some_name,然后您可以回滚到该保存点。