在由CALL
命令调用的过程中,以及在匿名代码块中,
可以使用COMMIT
和ROLLBACK
命令结束事务。
使用这些命令结束事务后,会自动启动一个新事务,因此没有单独的START TRANSACTION
命令。
(注意,PL/oraSQL中BEGIN
和END
具有不同的含义。)
以下是一个简单的示例:
CREATE OR REPLACE PROCEDURE transaction_test1(b int) IS BEGIN FOR i IN 0..9 LOOP INSERT INTO test1 (a) VALUES (i); IF i < b THEN COMMIT; ELSE ROLLBACK; END IF; END LOOP; END; / CALL transaction_test1(3);
本文主要介绍了游标操作和事务操作(提交和回滚)的组合。主要分为以下五类:
功能
在函数中调用函数:不支持。
函数调用过程:不支持。
函数包中的函数和存储过程:
传递函数:不支持;
包调整过程:不支持。
存储过程
在存储过程中调用函数:不支持。
存储过程调用过程:支持。
在存储过程中调用包中的函数和存储过程:
传递函数:不支持;
包调整过程:不支持。
匿名块
在匿名块中调用函数:不支持。
匿名块中间调整过程:支持。
在匿名块中调用包中的函数和存储过程:
传递函数:不支持;
包调整过程:不支持。
包中的函数
包函数调用函数:不支持。
包函数调用存储过程:不支持。
包函数调用包中的函数和存储过程:
传递函数:不支持;
包调整过程:不支持。
包中的存储过程
包存储过程调用者:不支持。
包存储过程调用存储过程:支持。
包存储过程传递函数和包中的存储过程:
传递函数:不支持;
包调整过程:不支持。
要使用游标操作和事务操作(提交和回滚),并且 lightdb_dblevel_syntax_compatible_type 的值为 oracle, 需要将 search_path 设置为以下内容: SET search_path TO public, oracle;
在匿名块中不支持与存储过程相同的方式调用函数,例如:
create or replace function func return int as begin dbms_output.put_line ('This is just a test'); end; / begin func(); dbms_output.put_line ('This is just a test'); end; /
游标声明和定义的包说明:
在声明包时,不能直接在包中声明游标;
在定义包体时,不能在包体的全局区域直接定义游标变量。
目前无法同时使用存储过程和插件 auto_explain。
示例:调用存储过程
--preconditional -- the value of lightdb_dblevel_syntax_compatible_type must be oracle create extension IF NOT EXISTS orafce; SET search_path TO public, oracle; create table ltbench_accounts(id int, abalance int); --insert declare irevert int := 9999; icount int := 1000; begin loop execute immediate 'insert into ltbench_accounts values(:er,:rt)' using irevert, icount; icount := icount - 1; irevert := irevert -1; exit when icount < 1; end loop; end; / --commit、rollback create or replace procedure tt_try_proc as CURSOR c1 IS SELECT * FROM ltbench_accounts; CURSOR c2 IS SELECT * FROM ltbench_accounts; emp_rec ltbench_accounts%ROWTYPE; BEGIN OPEN c2; OPEN c1; UPDATE ltbench_accounts SET id = 25 WHERE abalance = 12; rollback; UPDATE ltbench_accounts SET id = 17 WHERE abalance = 13; commit; LOOP FETCH c1 INTO emp_rec; EXIT WHEN c1%NOTFOUND; dbms_output.put_line ('emp_rec.id = ' || emp_rec.id || 'emp_rec.abalance = ' || emp_rec.abalance); UPDATE ltbench_accounts SET id = 23 WHERE abalance = 12; rollback; END LOOP; LOOP FETCH c2 INTO emp_rec; EXIT WHEN c2%NOTFOUND; dbms_output.put_line ('emp_rec.id = ' || emp_rec.id || 'emp_rec.abalance = ' || emp_rec.abalance); UPDATE ltbench_accounts SET id = 18 WHERE abalance = 13; commit; END LOOP; commit; rollback; END; / --call procedure in procedure create or replace procedure tt_try_dproc as begin tt_try_proc(); dbms_output.put_line ('This is just a test'); end; / call tt_try_dproc();
示例:在存储过程中调用存储在包中的存储过程
--preconditional create table test(x int, y varchar(100)); insert into test values(1, 'One'); insert into test values(2, 'Two'); insert into test values(3, 'Three'); --create package create or replace package pkg is CURSOR c1 IS SELECT x,y FROM test; function c_open return int; function c_fetch return int; procedure c_open_fetch; end; / --create package boby create or replace package body pkg IS function c_open return int as begin OPEN c1; return 0; end; --The fetch in the package, the cursor will not be cleared function c_fetch return int AS v_x test.x%TYPE; v_y test.y%TYPE; begin LOOP FETCH c1 INTO v_x, v_y; EXIT WHEN c1%NOTFOUND; dbms_output.put_line( v_x || '.' || v_y); END LOOP; --CLOSE c1; return 0; end; procedure c_open_fetch as v_x test.x%TYPE; v_y test.y%TYPE; BEGIN OPEN c1; COMMIT; LOOP FETCH c1 INTO v_x, v_y; EXIT WHEN c1%NOTFOUND; dbms_output.put_line( v_x || '.' || v_y); IF c1%FOUND THEN UPDATE test SET x = 4 WHERE y = 'Two'; ROLLBACK; END IF; END LOOP; CLOSE c1; end; begin dbms_output.put_line('initializer'); UPDATE test SET x = 5 WHERE y = 'Two'; COMMIT; end; / --procedure of package callled by procedure create or replace procedure tt_try_proc as begin pkg.c_open_fetch(); dbms_output.put_line ('This is just a test'); end; / call tt_try_proc();
示例:匿名块中间调优过程
begin tt_try_proc(); end; /
示例:在匿名块中调用包中的存储过程
--procedure of package called by anonymous block begin pkg.c_open_fetch(); dbms_output.put_line ('This is just a test'); end; /
示例:包存储过程调用存储过程
--create package create or replace package pkg_proc is CURSOR c1 IS SELECT x,y FROM test; procedure c_proc; end; / --create package boby create or replace package body pkg_proc IS procedure c_proc as v_x test.x%TYPE; v_y test.y%TYPE; BEGIN OPEN c1; COMMIT; LOOP tt_try_proc(); FETCH c1 INTO v_x, v_y; EXIT WHEN c1%NOTFOUND; dbms_output.put_line( v_x || '.' || v_y); IF c1%FOUND THEN UPDATE test SET x = 4 WHERE y = 'Two'; ROLLBACK; END IF; END LOOP; CLOSE c1; end; begin dbms_output.put_line('initializer'); UPDATE test SET x = 5 WHERE y = 'Two'; COMMIT; end; / call pkg_proc.c_proc();
示例:包存储过程在包中传递存储过程
--procedure of package called by procedure of package --create package of pkg_proc create or replace package pkg_proc is CURSOR c1 IS SELECT x,y FROM test; procedure c_proc; end; / --create package boby of pkg_proc create or replace package body pkg_proc IS procedure c_proc as v_x test.x%TYPE; v_y test.y%TYPE; BEGIN OPEN c1; COMMIT; LOOP FETCH c1 INTO v_x, v_y; EXIT WHEN c1%NOTFOUND; dbms_output.put_line( v_x || '.' || v_y); IF c1%FOUND THEN UPDATE test SET x = 4 WHERE y = 'Two'; ROLLBACK; END IF; END LOOP; CLOSE c1; end; begin dbms_output.put_line('initializer'); UPDATE test SET x = 5 WHERE y = 'Two'; COMMIT; end; / --create package of pkg_call_proc create or replace package pkg_call_proc is CURSOR c1 IS SELECT x,y FROM test; procedure c_call_proc; end; / --create package boby of pkg_call_proc create or replace package body pkg_call_proc IS procedure c_call_proc as v_x test.x%TYPE; v_y test.y%TYPE; BEGIN OPEN c1; COMMIT; LOOP pkg_proc.c_proc(); FETCH c1 INTO v_x, v_y; EXIT WHEN c1%NOTFOUND; dbms_output.put_line( v_x || '.' || v_y); IF c1%FOUND THEN UPDATE test SET x = 4 WHERE y = 'Two'; ROLLBACK; END IF; END LOOP; CLOSE c1; end; begin dbms_output.put_line('initializer'); UPDATE test SET x = 5 WHERE y = 'Two'; COMMIT; end; / call pkg_call_proc.c_call_proc();
示例:声明包时,不能直接在包中声明游标
--Declare cursors in packages using sys_refcursor --error create or replace package pkg is c1 sys_refcursor; function c_open return int; function c_fetch return int; procedure c_open_fetch; end; /
示例:在定义包体时,不能直接在包体的全局区域定义游标变量
--在包体内使用sys_refcursor声明游标变量 create or replace package pkg is function c_open return int; function c_fetch return int; procedure c_open_fetch; end; / --错误示例 create or replace package body pkg IS c1 sys_refcursor; function c_open return int as begin OPEN c1 for SELECT x,y FROM test; return 0; end; function c_fetch return int AS v_x test.x%TYPE; v_y test.y%TYPE; begin LOOP FETCH c1 INTO v_x, v_y; EXIT WHEN c1%NOTFOUND; dbms_output.put_line( v_x || '.' || v_y); END LOOP; --CLOSE c1; return 0; end; procedure c_open_fetch as v_x test.x%TYPE; v_y test.y%TYPE; BEGIN OPEN c1 for SELECT x,y FROM test; COMMIT; LOOP FETCH c1 INTO v_x, v_y; EXIT WHEN c1%NOTFOUND; dbms_output.put_line( v_x || '.' || v_y); IF c1%FOUND THEN UPDATE test SET x = 4 WHERE y = 'Two'; ROLLBACK; END IF; END LOOP; CLOSE c1; end; begin dbms_output.put_line('initializer'); UPDATE test SET x = 5 WHERE y = 'Two'; COMMIT; end; /
AUTONOMOUS_TRANSACTION
语法改变事务中子程序的执行方式。通过此语法,子程序的提交,撤销可以独立于主事务。
此功能从版本24.1开始支持,在Oracle模式下,此语法可应用于不含游标类型参数的函数和存储过程。
语法
PRAGMA AUTONOMOUS_TRANSACTION;
示例如下:
CREATE OR REPLACE PROCEDURE lower_salary (emp_id NUMBER, amount NUMBER) AS PRAGMA AUTONOMOUS_TRANSACTION; BEGIN UPDATE employees SET salary = salary - amount WHERE employee_id = emp_id; COMMIT; END lower_salary; / CREATE OR REPLACE FUNCTION log_msg (msg VARCHAR2) RETURN VARCHAR2 IS PRAGMA AUTONOMOUS_TRANSACTION; BEGIN INSERT INTO debug_output (message) VALUES (msg); COMMIT; RETURN msg; END; / DECLARE my_emp_id NUMBER(6); my_last_name VARCHAR2(25); my_count NUMBER; BEGIN my_emp_id := 120; SELECT debugging.log_msg(last_name) INTO my_last_name FROM employees WHERE employee_id = my_emp_id; /* 即使回滚debug_output表仍然被插入数据 */ ROLLBACK; END; /