事务块中语句错误的回滚行为

John Doe 六月 26, 2024

摘要:在本文中,我们将学习事务块中语句错误的回滚行为,以及 PostgreSQL 和 Oracle 之间的区别。

目录

PostgreSQL - ERROR: current transaction is aborted

通常,您制造的任何错误都会引发异常,并导致当前事务被标记为中止。这是理智和预期的行为,但如果它发生在您运行大型事务并输入了错误内容时,这可能会非常的烦人!此时,您唯一能做的就是回滚事务并丢弃所有工作。

当您在 PostgreSQL 中遇到错误时,事务是无法继续的。例如:

DROP TABLE IF EXISTS demo;

START TRANSACTION;
CREATE TABLE demo(n, t) AS SELECT 1 n, current_timestamp t;
ALTER TABLE demo ADD UNIQUE(n);

SELECT * FROM demo;
 n |               t
---+-------------------------------
 1 | 2021-06-26 18:15:07.207671+08
(1 row)

INSERT INTO demo VALUES (2, current_timestamp);
SELECT * FROM demo;
 n |               t
---+-------------------------------
 1 | 2021-06-26 18:15:07.207671+08
 2 | 2021-06-26 18:15:07.207671+08
(2 rows)

INSERT INTO demo VALUES (1, current_timestamp);
ERROR:  duplicate key value violates unique constraint "demo_n_key"
DETAIL:  Key (n)=(1) already exists.

SELECT * FROM demo;
ERROR:  current transaction is aborted, commands ignored until end of transaction block

ROLLBACK;

SELECT * FROM demo;
ERROR:  relation "demo" does not exist
LINE 1: SELECT * FROM demo;

在这里我们进行了回滚。但其实也可以提交来终止事务,但它无论如何都会回滚:

COMMIT;

SELECT * FROM demo;
ERROR:  relation "demo" does not exist
LINE 1: SELECT * FROM demo;

Oracle 语句级回滚

如果在执行过程中的任何时候,SQL 语句发生错误,则该语句的所有更改都将回滚。回滚的效果就好像该语句从未执行过一样。这是一种语句级的回滚。

在 SQL 语句执行过程中发生的错误会导致语句级回滚。(此类错误的一个示例是,尝试在主键中插入重复值。在 SQL 语句解析过程中发生的错误(如语法错误)尚未执行,因此不会导致语句级回滚。涉及死锁(争用相同数据)的单个 SQL 语句也可能导致语句级回滚。

失败的 SQL 语句只会导致丢失它自己执行的任何工作;它不会导致在当前事务中丢失之前的任何工作。如果该语句是 DDL 语句,则不会撤消紧接在它前面的隐式提交。

在 Oracle 中,在一次用户调用中有一个语句失败时,将会回滚该用户调用所做的修改,但不会回滚之前的修改。事务还可以继续(如重试,或执行替代的更改),例如:

CREATE TABLE DEMO AS SELECT 1 n, current_timestamp t FROM dual;
ALTER TABLE DEMO ADD UNIQUE(n);

SELECT * FROM DEMO;
         N T
---------- -----------------------------------
         1 02-AUG-21 11.04.16.507292 PM +00:00

INSERT INTO DEMO VALUES (2, current_timestamp);

SELECT * FROM DEMO;
         N T
---------- -----------------------------------
         1 02-AUG-21 11.04.16.507292 PM +00:00
         2 02-AUG-21 11.04.16.601105 PM +00:00

INSERT INTO DEMO VALUES (1, current_timestamp);
ERROR at line 1:
ORA-00001: unique constraint (DEMO.SYS_C007847) violated

SELECT * FROM DEMO;
         N T
---------- -----------------------------------
         1 02-AUG-21 11.04.16.507292 PM +00:00
         2 02-AUG-21 11.04.16.601105 PM +00:00