根据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
命令并且每次都导致新的交易?
答案 0 :(得分:8)
为了准备工作,COPY
和PREPARE
必须在同一会话中。由于你的问题缺乏具体的命令,我假设你写的时候:
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
,然后您可以回滚到该保存点。