Oracle EBS 自治事务

自治事务程序主要是自主性,那就是,独立于主要的事务。之所以独立,或者提交之后会影响其他事务处理,本质在于它本身符合编译指令的规则,也就是说它属于在编译阶段就执行的指令,而不是在运行阶段执行的。

当自治事务行使时,主要的事务处理是暂缓状态的。自治事务完全独立于主要的事务处理。他们不分享锁、资源或者是提交的独立性。自治事务处理不会影响主要的事务处理。

当自治事务提交时,自治事务的改变会对其他的事物处理显而易见的。只有当它的隔离水平是READ COMMITTED(默认值)时,当它重新运行时对主要的事务处理而言是可见的。

注意以下几点:

编译指令在编译的时候就完成了,而不是在运行的时候完成的。他们经由编译器传递消息;

编译指示不能作用在整个包上,但是你可以作用在包里的每个子程序;

编译指示不能作用整个object类型上,但是可以作用在每种SQL object 类型上;

不像普通的触发器,一个自动触发器可以包含事务控制描述,像是提交和回滚,可以通过 EXECUTE IMMEDIATE 进行DDL操作,像是 create 或者 drop

在主要的事务中,会滚到一个定位在自治事务子程序之前的保留点,是不会回滚掉自治事务。记住,自治事务是完全独立于主要事务的;

如果一个自治事务尝试使用被主要事务处理占用的资源(只能当自治退出后才能重启),那么会造成死锁。数据库会抛出在自治事务的异常。如果异常无法处理那么会进行回滚;

如果你在没有提交或者回滚是尝试退出一个活跃状态的自治事务,数据库会抛出异常。如果异常无法处理或者因为其他无法预料的异常事务处理结束,那么该事物会回滚;

当你的自治事务是开启状态是你不能对你的自治规则执行管线 row声明。在执行管线 PIPE ROW声明钱你必须关掉自治事务。在执行 PIPE ROW 生命史提交或者回滚自治事务是普遍实现的。

1. 自治事务方法

 

CREATE OR REPLACE PACKAGE emp_actions AS  -- package specification
   FUNCTION raise_salary (emp_id NUMBER, sal_raise NUMBER)
     RETURN NUMBER;
END emp_actions;
/
CREATE OR REPLACE PACKAGE BODY emp_actions AS  -- package body
-- code for function raise_salary
   FUNCTION raise_salary (emp_id NUMBER, sal_raise NUMBER)
     RETURN NUMBER IS
     PRAGMA AUTONOMOUS_TRANSACTION;
     new_sal NUMBER(8,2);
   BEGIN
     UPDATE employees SET salary =
       salary + sal_raise WHERE employee_id = emp_id;
     COMMIT;
     SELECT salary INTO new_sal FROM employees
       WHERE employee_id = emp_id;
     RETURN new_sal;
   END raise_salary;
END emp_actions;

  

CREATE TABLE debug_output (msg VARCHAR2(200));

-- create the package spec
CREATE PACKAGE debugging AS
   FUNCTION log_msg (msg VARCHAR2) RETURN VARCHAR2;
   PRAGMA RESTRICT_REFERENCES(log_msg, WNDS, RNDS);
END debugging;
/
-- create the package body
CREATE PACKAGE BODY debugging AS
   FUNCTION log_msg (msg VARCHAR2) RETURN VARCHAR2 IS
      PRAGMA AUTONOMOUS_TRANSACTION;
   BEGIN
      -- the following insert does not violate the constraint
      -- WNDS because this is an autonomous routine
      INSERT INTO debug_output VALUES (msg);
      COMMIT;
      RETURN msg;
   END;
END debugging;

  

 

2. 自治事务过程

 

CREATE 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;

  

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;
-- even if you roll back in this scope, the insert into 'debug_output' remains
-- committed because it is part of an autonomous transaction
   ROLLBACK;
END;

  

 

3. 自治事务块

 

 

 

4. 自治事务触发器

 

CREATE TABLE emp_audit ( emp_audit_id NUMBER(6), up_date DATE, 
                         new_sal NUMBER(8,2), old_sal NUMBER(8,2) );

CREATE OR REPLACE TRIGGER audit_sal
   AFTER UPDATE OF salary ON employees FOR EACH ROW
DECLARE 
   PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
-- bind variables are used here for values
   INSERT INTO emp_audit VALUES( :old.employee_id, SYSDATE, 
                                 :new.salary, :old.salary );
  COMMIT;
END;

  

 

下面拿一个例外举例说明一下事务处理的用途。

例外声明关联着用户定义的例外名称和 oracle数据库的错误编码。你可以拦截任何oracle数据量的错误数字然后写一个例外处理他,而不是使用others处理。

其中的错误数据是指错误数字任何有效的oracle 数据库错误数字,这些同方法 SQLCODE 返回的错误数字相同(通常是负数)。例外名称是指例外名称是指定义这个声明是一个编译指示。编译指示在编译是处理,而不是在运行时间时处理。这一点和自治事务运行一样。

下面的例子展示了你可以执行一个DML操作返回的数字,而不是一些操作碰到错误的时候停下来。这个例子中例外是 ORA-24381

在执行是所有的抛出的意外被保存在游标attribute %BULK_EXCEPTIONS 。每一个记录有两块。

%BULK_EXCEPTIONS(i).ERROR_INDEX 存储的是在异常被抛出是后的 FORALL声明中的循环;

%BULK_EXCEPTIONS(i).ERROR_CODE 中存储的是 ORACLE 数据库相关的错误编码;

例外的个数被保存在%BULK_EXCEPTIONS.COUNT ,他计数从1开始。

个体的错误信息或者任何可替代的参数,不被保存。但是错误信息可使用 ERROR_CODE 看到。

在如下例子里,plsql抛出了一个定义好的异常,因为更新数据太大对于将数据插入到job_id列。在FORALL声明后 SQL%BULK_EXCEPTIONS.COUNT 返回2. SQL%BULK_EXCEPTIONS 内容是 (7,12899) and (13,12899)

 

 

DECLARE
   deadlock_detected EXCEPTION;
   PRAGMA EXCEPTION_INIT(deadlock_detected, -60);
BEGIN
   NULL; -- Some operation that causes an ORA-00060 error
EXCEPTION
   WHEN deadlock_detected THEN
      NULL; -- handle the error
END;
/
-- Temporary table for this example:
CREATE TABLE emp_temp AS SELECT * FROM employees;

DECLARE
  TYPE empid_tab IS TABLE OF employees.employee_id%TYPE;
  emp_sr empid_tab;

  -- Exception handler for ORA-24381:
  errors     NUMBER;
  dml_errors EXCEPTION;
  PRAGMA EXCEPTION_INIT(dml_errors, -24381);
BEGIN
  SELECT employee_id
      BULK COLLECT INTO emp_sr FROM emp_temp
        WHERE hire_date < '30-DEC-94';

  -- Add '_SR' to job_id of most senior employees:
  FORALL i IN emp_sr.FIRST..emp_sr.LAST SAVE EXCEPTIONS
    UPDATE emp_temp SET job_id = job_id || '_SR' 
      WHERE emp_sr(i) = emp_temp.employee_id;
  -- If errors occurred during FORALL SAVE EXCEPTIONS,
  -- a single exception is raised when the statement completes.

EXCEPTION
  -- Figure out what failed and why
  WHEN dml_errors THEN
   errors := SQL%BULK_EXCEPTIONS.COUNT;
   DBMS_OUTPUT.PUT_LINE
     ('Number of statements that failed: ' || errors);
   FOR i IN 1..errors LOOP
      DBMS_OUTPUT.PUT_LINE('Error #' || i || ' occurred during '||
         'iteration #' || SQL%BULK_EXCEPTIONS(i).ERROR_INDEX);
      DBMS_OUTPUT.PUT_LINE('Error message is ' ||
        SQLERRM(-SQL%BULK_EXCEPTIONS(i).ERROR_CODE));
   END LOOP;
END;
/
DROP TABLE emp_temp;

The output from the example is similar to:

Number of statements that failed: 2
Error #1 occurred during iteration #7
Error message is ORA-12899: value too large for column
Error #2 occurred during iteration #13
Error message is ORA-12899: value too large for column

  

 

猜你喜欢

转载自www.cnblogs.com/jenrry/p/10021227.html