3

PostgreSQL 文档手册http://www.postgresql.org/docs/8.3/interactive/populate.html上的以下链接表明,要在 postgreSQL 中禁用自动提交,您只需将所有插入语句放在 BEGIN 中即可;和承诺;

但是,我很难捕获 BEGIN 之间可能发生的任何异常;犯罪; 如果发生错误(例如尝试插入重复的 PK),我无法显式调用 ROLLBACK 或 COMMIT 命令。尽管所有的插入语句都会自动回滚,但 PostgreSQL 仍然需要显式调用 COMMIT 或 ROLLBACK 命令,然后才能考虑终止事务。否则,脚本必须等待事务超时,此后执行的任何语句都会引发错误。

在存储过程中,您可以使用 EXCEPTION 子句来执行此操作,但同样不适用于我执行批量插入的情况。我已经尝试过了,异常块对我不起作用,因为发生错误后执行的下一条语句无法执行并出现错误:

ERROR:  current transaction is aborted, commands ignored until end of transaction block

事务保持打开状态,因为它没有通过调用 COMMIT 或 ROLLBACK 明确完成;

这是我用来测试的代码示例:

BEGIN;
  SET search_path TO testing;
  INSERT INTO friends (id, name) VALUES (1, 'asd');
  INSERT INTO friends (id, name) VALUES (2, 'abcd');
    INSERT INTO friends (id, nsame) VALUES (2, 'abcd'); /*note the deliberate mistake in  attribute name and also the deliberately repeated pk value number 2*/
EXCEPTION /* this part does not work for me */
    WHEN OTHERS THEN
        ROLLBACK;   
COMMIT;

当使用这种技术时,我真的必须保证所有语句都会成功吗?为什么会这样?没有办法捕获错误并显式调用回滚吗?

谢谢

4

2 回答 2

2

如果您在开始和提交之间执行此操作,那么所有内容都会在发生异常时自动回滚。摘自您发布的网址:“在一个事务中进行所有插入的另一个好处是,如果插入一行失败,那么插入到该点的所有行的插入将被回滚,所以你不会被部分加载的数据卡住了。”

于 2012-03-30T15:16:18.017 回答
0

当我初始化数据库时,即创建一系列表/视图/函数/触发器/等。和/或加载初始数据,我总是使用 psql 和它的变量来控制流程。我总是补充:

\set ON_ERROR_STOP

到我的脚本的顶部,所以每当我遇到任何异常时,psql 都会中止。看起来这对您的情况也可能有所帮助。

在需要进行一些异常处理的情况下,我会使用这样的匿名代码块

DO $$DECLARE _rec record;
BEGIN
FOR _rec IN SELECT * FROM schema WHERE schema_name != 'master' LOOP
    EXECUTE 'DROP SCHEMA '||_rec.schema_name||' CASCADE';
END LOOP;
EXCEPTION WHEN others THEN
NULL;
END;$$;
DROP SCHEMA master CASCADE;
于 2012-03-30T19:53:46.447 回答