Oracle和PostgreSQL中不同的默认错误处理
在PL/SQL(PL/pgSQL)代码中遇到错误后,我比较了Oracle和PostgreSQL的默认行为。为此,我编写了一个类似于Oracle和PostgreSQL的代码,如下所示 Oracle代码(): PostgreSQL代码(): 注意:在PostgreSQL中,我另外运行了Oracle和PostgreSQL中不同的默认错误处理,oracle,postgresql,plsql,transactions,plpgsql,Oracle,Postgresql,Plsql,Transactions,Plpgsql,在PL/SQL(PL/pgSQL)代码中遇到错误后,我比较了Oracle和PostgreSQL的默认行为。为此,我编写了一个类似于Oracle和PostgreSQL的代码,如下所示 Oracle代码(): PostgreSQL代码(): 注意:在PostgreSQL中,我另外运行了begintransaction语句来禁用自动提交,因为Oracle没有自动提交,我希望两个代码都是类似的 SELECT*fromtable1查询的结果在Oracle中是一行,在PostgreSQL中没有行 如您所见,
begintransaction
语句来禁用自动提交,因为Oracle没有自动提交,我希望两个代码都是类似的
SELECT*fromtable1
查询的结果在Oracle中是一行,在PostgreSQL中没有行
如您所见,Oracle和PostgreSQL中的类似代码给出了不同的结果。在默认错误处理中出现这种差异的原因是什么?在Oracle中,您使用的是两个单独的事务,第一个成功,但第二个失败。在PostgreSQL中,您显式地告诉它只使用一个事务并一起处理语句 在Oracle中,如果使用PL/SQL匿名块将语句分组到单个事务中:
START TRANSACTION;
INSERT INTO table1 VALUES (1);
/* set a savepoint we can revert to */
SAVEPOINT x;
CALL raise_error();
ROLLBACK TO SAVEPOINT x;
/* now the INSERT can be committed */
COMMIT;
开始
在表1中插入数值(1);
raise_error();
结束;
/
并且,在PostgreSQL中相当于:
DO
$$
BEGIN
INSERT INTO table1 VALUES (1);
CALL raise_error();
END;
$$ LANGUAGE plpgsql;
然后,表中将没有行,因为过程中的异常将回滚整个事务
或者,在Oracle中,您可以执行以下操作:
插入表1值(1);
声明
除以零例外;
PRAGMA EXCEPTION_INIT(除以0,-1476);
开始
raise_error();
例外情况
当除以0时
回降;
结束;
/
这将具有将两个事务回滚到最后一次提交的相同效果
dbfiddle在Oracle中,您使用的是两个单独的事务,第一个成功,但第二个失败。在PostgreSQL中,您显式地告诉它只使用一个事务并一起处理语句 在Oracle中,如果使用PL/SQL匿名块将语句分组到单个事务中:
START TRANSACTION;
INSERT INTO table1 VALUES (1);
/* set a savepoint we can revert to */
SAVEPOINT x;
CALL raise_error();
ROLLBACK TO SAVEPOINT x;
/* now the INSERT can be committed */
COMMIT;
开始
在表1中插入数值(1);
raise_error();
结束;
/
并且,在PostgreSQL中相当于:
DO
$$
BEGIN
INSERT INTO table1 VALUES (1);
CALL raise_error();
END;
$$ LANGUAGE plpgsql;
然后,表中将没有行,因为过程中的异常将回滚整个事务
或者,在Oracle中,您可以执行以下操作:
插入表1值(1);
声明
除以零例外;
PRAGMA EXCEPTION_INIT(除以0,-1476);
开始
raise_error();
例外情况
当除以0时
回降;
结束;
/
这将具有将两个事务回滚到最后一次提交的相同效果
dbfiddleOracle和PostgreSQL在这里的行为确实不同 Oracle有一个我称之为“语句级回滚”的东西:如果在事务内部运行的语句导致错误,则只回滚该语句的效果,事务继续 在PostgreSQL中,事务中的任何错误都会中止整个事务,因此只能回滚该事务,而不会产生任何影响。这更符合“要么全有,要么全无”的精神,但就我所见,SQL标准对此并不具体,因此这两种行为都可以争论 但是,您可以使用PostgreSQL中符合标准的保存点从事务中的错误中“恢复”:
START TRANSACTION;
INSERT INTO table1 VALUES (1);
/* set a savepoint we can revert to */
SAVEPOINT x;
CALL raise_error();
ROLLBACK TO SAVEPOINT x;
/* now the INSERT can be committed */
COMMIT;
但请注意,每个事务的处理次数不超过64次,否则性能可能会受到影响。Oracle和PostgreSQL在这里的表现确实不同 Oracle有一个我称之为“语句级回滚”的东西:如果在事务内部运行的语句导致错误,则只回滚该语句的效果,事务继续 在PostgreSQL中,事务中的任何错误都会中止整个事务,因此只能回滚该事务,而不会产生任何影响。这更符合“要么全有,要么全无”的精神,但就我所见,SQL标准对此并不具体,因此这两种行为都可以争论 但是,您可以使用PostgreSQL中符合标准的保存点从事务中的错误中“恢复”:
START TRANSACTION;
INSERT INTO table1 VALUES (1);
/* set a savepoint we can revert to */
SAVEPOINT x;
CALL raise_error();
ROLLBACK TO SAVEPOINT x;
/* now the INSERT can be committed */
COMMIT;
但请注意,您(不超过64个)的每个事务,否则性能可能会受到影响。您是否在Oracle中启动了事务?在PostgreSQL示例中,事务失败,因此插入失败。这意味着表仍然是空的。@FrankHeikens,在Oracle中,事务会自动启动。PostgreSQL、MySQL和SQL Server都有自动提交功能,但Oracle没有自动提交功能:这种Oracle行为取决于DBFIDLE客户端在异常后是否继续,这不是大多数客户端的默认行为。在sql*plus中,只要SQLERROR继续回滚,就可以通过
获得Postgres行为。您是否在Oracle中启动了事务?在PostgreSQL示例中,事务失败,因此插入失败。这意味着表仍然是空的。@FrankHeikens,在Oracle中,事务会自动启动。PostgreSQL、MySQL和SQL Server都有自动提交功能,但Oracle没有自动提交功能:这种Oracle行为取决于DBFIDLE客户端在异常后是否继续,这不是大多数客户端的默认行为。在sql*plus中,只要SQLERROR继续回滚,您就可以通过获得Postgres行为。有关Oracle文档的更多详细信息,请参阅