由 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