ROLLBACK 命令撤消当前事务期间执行的所有数据库更新,并结束当前事务。
ROLLBACK [ WORK ];
ROLLBACK 命令可在匿名块、存储过程或函数中使用。在 SPL 程序内,它可出现在可执行部分和/或异常部分中。
在以下示例中,异常部分包含 ROLLBACK 命令。即使前两个 INSERT 命令成功执行,第三个命令也会因匿名块中所有 INSERT 命令的回滚而导致异常。
\set AUTOCOMMIT off
SET polar_comp_stmt_level_tx TO on;
BEGIN
INSERT INTO dept VALUES (50, 'FINANCE', 'DALLAS');
INSERT INTO dept VALUES (60, 'MARKETING', 'CHICAGO');
INSERT INTO dept VALUES (70, 'HUMAN RESOURCES', 'CHICAGO');
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
DBMS_OUTPUT.PUT_LINE('SQLERRM: ' || SQLERRM);
DBMS_OUTPUT.PUT_LINE('SQLCODE: ' || SQLCODE);
END;
SQLERRM: value too long for type character varying(14)
SQLCODE: 22001
SELECT * FROM dept;
deptno | dname | loc
--------+------------+----------
10 | ACCOUNTING | NEW YORK
20 | RESEARCH | DALLAS
30 | SALES | CHICAGO
40 | OPERATIONS | BOSTON
(4 rows)
下面是一个更复杂的示例,它使用了 COMMIT 和 ROLLBACK。首先,创建了以下存储过程,其中插入了一个新员工。
\set AUTOCOMMIT off
SET polar_comp_stmt_level_tx TO on;
CREATE OR REPLACE PROCEDURE emp_insert (
p_empno IN emp.empno%TYPE,
p_ename IN emp.ename%TYPE,
p_job IN emp.job%TYPE,
p_mgr IN emp.mgr%TYPE,
p_hiredate IN emp.hiredate%TYPE,
p_sal IN emp.sal%TYPE,
p_comm IN emp.comm%TYPE,
p_deptno IN emp.deptno%TYPE
)
IS
BEGIN
INSERT INTO emp VALUES (
p_empno,
p_ename,
p_job,
p_mgr,
p_hiredate,
p_sal,
p_comm,
p_deptno);
DBMS_OUTPUT.PUT_LINE('Added employee...');
DBMS_OUTPUT.PUT_LINE('Employee # : ' || p_empno);
DBMS_OUTPUT.PUT_LINE('Name : ' || p_ename);
DBMS_OUTPUT.PUT_LINE('Job : ' || p_job);
DBMS_OUTPUT.PUT_LINE('Manager : ' || p_mgr);
DBMS_OUTPUT.PUT_LINE('Hire Date : ' || p_hiredate);
DBMS_OUTPUT.PUT_LINE('Salary : ' || p_sal);
DBMS_OUTPUT.PUT_LINE('Commission : ' || p_comm);
DBMS_OUTPUT.PUT_LINE('Dept # : ' || p_deptno);
DBMS_OUTPUT.PUT_LINE('----------------------');
END;
请注意,此存储过程没有异常部分,因此可能发生的任何错误都会向上传播到调用程序。
将运行以下匿名块。请注意,在对 emp_insert 存储过程和异常部分中的 ROLLBACK 命令进行所有调用后使用了 COMMIT 命令。
BEGIN
emp_insert(9601,'FARRELL','ANALYST',7902,'03-MAR-08',5000,NULL,40);
emp_insert(9602,'TYLER','ANALYST',7900,'25-JAN-08',4800,NULL,40);
COMMIT;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('SQLERRM: ' || SQLERRM);
DBMS_OUTPUT.PUT_LINE('An error occurred - roll back inserts');
ROLLBACK;
END;
Added employee...
Employee # : 9601
Name : FARRELL
Job : ANALYST
Manager : 7902
Hire Date : 03-MAR-08 00:00:00
Salary : 5000
Commission :
Dept # : 40
----------------------
Added employee...
Employee # : 9602
Name : TYLER
Job : ANALYST
Manager : 7900
Hire Date : 25-JAN-08 00:00:00
Salary : 4800
Commission :
Dept # : 40
----------------------
以下 SELECT 命令显示员工 Farrell 和 Tyler 已成功添加。
SELECT * FROM emp WHERE empno > 9600;
empno | ename | job | mgr | hiredate | sal | comm | deptno
-------+---------+---------+------+--------------------+---------+------+--------
9601 | FARRELL | ANALYST | 7902 | 03-MAR-08 00:00:00 | 5000.00 | | 40
9602 | TYLER | ANALYST | 7900 | 25-JAN-08 00:00:00 | 4800.00 | | 40
(2 rows)
现在,执行以下匿名块:
BEGIN
emp_insert(9603,'HARRISON','SALESMAN',7902,'13-DEC-07',5000,3000,20);
emp_insert(9604,'JARVIS','SALESMAN',7902,'05-MAY-08',4800,4100,11);
COMMIT;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('SQLERRM: ' || SQLERRM);
DBMS_OUTPUT.PUT_LINE('An error occurred - roll back inserts');
ROLLBACK;
END;
Added employee...
Employee # : 9603
Name : HARRISON
Job : SALESMAN
Manager : 7902
Hire Date : 13-DEC-07 00:00:00
Salary : 5000
Commission : 3000
Dept # : 20
----------------------
SQLERRM: insert or update on table "emp" violates foreign key constraint "emp_ref_dept_fk"
An error occurred - roll back inserts
针对表运行的 SELECT 命令产生以下输出:
SELECT * FROM emp WHERE empno > 9600;
empno | ename | job | mgr | hiredate | sal | comm | deptno
-------+---------+---------+------+--------------------+---------+------+--------
9601 | FARRELL | ANALYST | 7902 | 03-MAR-08 00:00:00 | 5000.00 | | 40
9602 | TYLER | ANALYST | 7900 | 25-JAN-08 00:00:00 | 4800.00 | | 40
(2 rows)
异常部分中的 ROLLBACK 命令成功撤消员工 Harrison 的插入。另请注意,员工 Farrell 和 Tyler 仍在表中,因为第一个匿名块中的 COMMIT 命令使其插入成为永久性的。
说明 如果运行时堆栈上存在 Oracle 样式的 SPL 过程,则在 PLPGSQL 存储过程中执行 COMMIT 或 ROLLBACK 将会引发错误。