1. 程式人生 > >Oracle EBS 自治事務

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