在 Oracle 中,当 SQL 命令中出现运行时错误时,将回滚该单个命令所引起的数据库上的所有更新。这称为语句级别事务隔离。例如,如果单个 UPDATE 命令成功更新五行,但尝试更新第六行时出现异常,则将回滚此 UPDATE 命令对所有六行进行的更新。之前尚未提交或回滚的 SQL 命令的效果将挂起,直到执行了 COMMIT 或 ROLLBACK 命令。

在 PostgreSQL 中,如果在执行 SQL 命令时发生异常,则将回滚自事务开始以来的数据库上的所有更新。此外,该事务停留在中止状态,必须发出 COMMIT 或 ROLLBACK 命令,才能开始其他事务。

如果 edb_stmt_level_tx 设置为 TRUE,则异常不会自动回滚之前未提交的数据库更新,这模拟 Oracle 行为。如果 edb_stmt_level_tx 设置为 FALSE,则异常将回滚未提交的数据库更新。

注意 仅在绝对必要时才使用设置为 TRUE 的 edb_stmt_level_tx,因为这可能会对性能造成负面影响。

在 PSQL 中运行的以下示例显示当 edb_stmt_level_tx 为 FALSE 时,第二个 INSERT 命令中止还会回滚第一个 INSERT 命令。请注意,在 PSQL 中,必须发出命令 \set AUTOCOMMIT off,否则每个语句会自动提交,违背了此 edb_stmt_level_tx 的效果演示的目的。

\set AUTOCOMMIT off
SET edb_stmt_level_tx TO off;

INSERT INTO emp (empno,ename,deptno) VALUES (9001, 'JONES', 40);
INSERT INTO emp (empno,ename,deptno) VALUES (9002, 'JONES', 00);
ERROR:  insert or update on table
"emp" violates foreign key constraint "emp_ref_dept_fk"
DETAIL:  Key (deptno)=(0) is not present in table "dept".

COMMIT;
SELECT empno, ename, deptno FROM emp WHERE empno > 9000;

empno | ename | deptno
-------+-------+--------
(0 rows)        

在 edb_stmt_level_tx 设置为 TRUE 的以下示例中,在第二个 INSERT 命令出错后,尚未回滚第一个 INSERT 命令。此时,可以提交或回滚第一个 INSERT 命令。

\set AUTOCOMMIT off
SET edb_stmt_level_tx TO on;

INSERT INTO emp (empno,ename,deptno) VALUES (9001, 'JONES', 40);
INSERT INTO emp (empno,ename,deptno) VALUES (9002, 'JONES', 00);
ERROR:  insert or update on table
"emp" violates foreign key constraint "emp_ref_dept_fk"
DETAIL:  Key (deptno)=(0) is not present in table "dept".

SELECT empno, ename, deptno FROM emp WHERE empno > 9000;

empno | ename | deptno
-------+-------+--------
  9001 | JONES |     40
(1 row)

COMMIT;       

可能已发出 ROLLBACK 命令而非 COMMIT 命令,在这种情况下,还已回滚员工编号 9001 的插入。