PostgreSQL文档手册http://www.postgresql.org/docs/8.3/interactive/populate.html中的以下链接说明要在postgreSQL中禁用自动提交,您只需将所有插入语句放在BEGIN中;和COMMIT;
但是我很难捕捉到BEGIN之间可能发生的任何异常;承诺;如果发生错误(比如尝试插入重复的PK),我无法显式调用ROLLBACK或COMMIT命令。虽然所有insert语句都会自动回滚,但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;
使用这种技术时,我真的必须保证所有的陈述都会成功吗?为什么会这样?是不是有办法捕获错误并显式调用回滚?
谢谢
答案 0 :(得分:2)
如果你在begin和commit之间执行它,那么在异常情况下会自动回滚所有内容。 摘自您发布的网址: “在一个事务中执行所有插入的另一个好处是,如果插入一行失败,那么插入到该点的所有行的插入将被回滚,因此您不会遇到部分加载的数据。 “
答案 1 :(得分:0)
当我初始化数据库时,即创建一系列表/视图/函数/触发器/等。和/或加载初始数据,我总是使用psql和它的Variables来控制流程。我总是补充说:
\set ON_ERROR_STOP
到我的脚本的顶部,所以每当我遇到任何异常时,psql都会中止。看起来这对你的情况也有帮助。
如果我需要进行一些异常处理,我会像这样使用anonymous code blocks:
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;