Oracle和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中没有行 如您所见,

在PL/SQL(PL/pgSQL)代码中遇到错误后,我比较了Oracle和PostgreSQL的默认行为。为此,我编写了一个类似于Oracle和PostgreSQL的代码,如下所示

Oracle代码():

PostgreSQL代码():

注意:在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时
回降;
结束;
/
这将具有将两个事务回滚到最后一次提交的相同效果


dbfiddle

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在这里的表现确实不同

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文档的更多详细信息,请参阅