1. 程式人生 > >oracle學習之道:如何在ORACLE中非同步呼叫儲存過程的方法

oracle學習之道:如何在ORACLE中非同步呼叫儲存過程的方法

 在ORACLE資料庫實際應用過程中,經常把業務處理邏輯的放在儲存過程,客戶端通過ADO進行呼叫。有些業務邏輯處理量大並且複雜,使客戶端呼叫儲存過程後,長時間沒有反應,也不知儲存過程執行狀態,本文講述如何在ORACLE通過任務和管道的應用,非同步呼叫儲存過程的方法。

  基本原理

  1.使用DBMS_JOB包將主處理儲存過程作為任務提交到任務佇列中。

  2.主處理儲存過程在執行過程中通過DBMS_PIPE包將處理情況放在管道中。

  3.監控儲存過程讀取管道,從而瞭解處理情況。

  4.本文沒有描述雙向通訊的方式,監控儲存過程可以通過管道傳送資訊給主處理儲存過程。

  具體實現測試

  建立測試環境

  1.對資料庫的ini進行相關修改,使系統的任務佇列功能開啟。對於Oracle9I,只需修設定資料庫的INI內的"JOB_QUEUE_PROCESSES=非0值",如"JOB_QUEUE_PROCESSES=10",對於ORACLE8I除設定例項ini檔案中的"JOB_QUEUE_PROCESSES=非0值"外,還需設定"job_queue_interval=1"。

  2. 設用使用者許可權

  由於使用ORACLE中特定的程式包,所以要注意要明文給於使用者系統許可權。對當前使用者(測試使用者),賦於以下權力EXECUTE DBMS_PIPE


  EXECUTE DBMS_LOCK 
  EXECUTE DBMS_JOB

  3. 建立模擬大業務處理儲存過程

  本儲存過程通過迴圈30次,呼叫DBMS_LOCK.SLEEP(1)(體眠1秒)和寫管道模擬大的處理過程。


  具體程式碼如下:CREATE OR REPLACE PROCEDURE maxpro AS 
  n integer; 
  status NUMBER; 
  BEGIN 
  FOR N IN 1..30 LOOP 
  DBMS_PIPE.PURGE('maxpro'); --清除原管道資訊 
  DBMS_PIPE.PACK_MESSAGE(N); --把資訊放入緩衝區 
  status:=DBMS_PIPE.SEND_MESSAGE('maxpro'); 
  DBMS_LOCK.SLEEP(1); 
  END LOOP; 
  DBMS_PIPE.PURGE('maxpro'); --清除原管道資訊 
  DBMS_PIPE.PACK_MESSAGE(999999); --把資訊放入緩衝區,用999999 表示過程完成 
  status:=DBMS_PIPE.SEND_MESSAGE('maxpro'); 

  END maxpro;

 4. 建立讀取管道動態瞭解處理狀態的儲存過程

  以下程式碼是對於maxpro儲存過程的狀態進行讀取的過程,主要使用讀取管道的方法,注意:status:= DBMS_PIPE.RECEIVE_MESSAGE('maxpro',0);中的"0"引數是很關鍵的,說明接受等待時間為0秒,表示,呼叫時如果沒有資訊不等待直接返回。


  具體程式碼如下:CREATE OR REPLACE PROCEDURE readmaxpro AS 
  n integer; 
  status integer; 
  begin

  --接受等待時間為1秒,可以為0,立即呼叫或DBMS_PIPE.


  RECEIVE_MESSAGE('mypipe') 等待100天 
  status:= DBMS_PIPE.RECEIVE_MESSAGE('maxpro',0); 
  --status為0為成功可以UNPACK_MESSAGE,1為超時沒有資料,2為資訊太大,3為內部錯誤 
  IF status <> 0 THEN 
  DBMS_OUTPUT.PUT_LINE('管道中現在沒有資訊返回'); 
  return; 
  END IF; 
  DBMS_PIPE.UNPACK_MESSAGE(n); 
  DBMS_OUTPUT.PUT_LINE('maxpro 的當前進行狀態為'|| n); 
  end;

  5.-起動模擬大業務處理儲存過程為後臺程序的儲存過程(BEGINMAXPRO)。通過DBMS_JOB.SUBMIT(JOB,'maxpro;',sysdate,NULL,FALSE);使"maxpro"為一個任務,在當前時間(sysdate)後執行,當然如果把sysdate改一具體時間,那就在具體時間執行


  具休程式碼如下:CREATE OR REPLACE PROCEDURE beginmaxpro AS 
  JOB BINARY_INTEGER; 
  BEGIN 
  DBMS_JOB.SUBMIT(JOB,'maxpro;',sysdate,NULL,FALSE); 
  DBMS_OUTPUT.PUT_LINE('佇列號碼JOB=' || JOB); 
  COMMIT; 
  end;

  SQL> call readmaxpro();


  SQL>

  2. 執行分析

  beginmaxpro(),將主處理儲存過程放入佇列的過程,執行後儲存程式馬上返回,maxpro儲存過程放在任務佇列中,並設定為在當前系統時間執行(馬上執行)。

  maxpro為主處理儲存過程,開始執行模擬大業務處理,處理過程中將處理進度資訊寫入管道。

  readmaxpro();為檢查狀態儲存過程,首先讀取資訊,如果資訊不存在,說明管道內沒有資訊可讀而退出;如果存在資訊則讀出資訊。

  本例子可以進行改進,輸出不通過DBMS_OUTPUT.PUT_LINE而是用返回值,那麼就可以在前端用ADO呼叫,釋出任務,任務過程中從客戶端讀取進度。程式碼如下:CREATE OR REPLACE PROCEDURE readmaxpro(p out intergr) AS


  n integer; 
  status integer; 
  begin 
  status:= DBMS_PIPE.RECEIVE_MESSAGE('maxpro',0); 
  IF status <> 0 THEN 
  P:=-1; 
  return; 
  END IF; 
  DBMS_PIPE.UNPACK_MESSAGE(p); 
  end;

程式碼執行

  1. 執行過程

  在CMD行輸入 sqlplus 根據提示登入

  設定DBMS_OUTPUT可見


  SQL> set serveroutput ON

以下是執行過程和相應的返回資訊


  SQL> call beginmaxpro();

  佇列號碼JOB=21

  呼叫完成。




  SQL> call readmaxpro();



  SQL> call readmaxpro();

以下是執行過程和相應的返回資訊


  SQL> call beginmaxpro();

  佇列號碼JOB=21

  呼叫完成。


  SQL> call readmaxpro();

  maxpro 的當前進行狀態為14

  呼叫完成。


 SQL> call readmaxpro();

  maxpro 的當前進行狀態為16

  呼叫完成。


  SQL> call readmaxpro();

  maxpro 的當前進行狀態為23

  呼叫完成。


  SQL> call readmaxpro();

  maxpro 的當前進行狀態為999999

  呼叫完成。


  SQL> call readmaxpro();

  管道中現在沒有資訊返回

  呼叫完成。


  SQL> call readmaxpro();




  SQL>

  2. 執行分析

  beginmaxpro(),將主處理儲存過程放入佇列的過程,執行後儲存程式馬上返回,maxpro儲存過程放在任務佇列中,並設定為在當前系統時間執行(馬上執行)。

  maxpro為主處理儲存過程,開始執行模擬大業務處理,處理過程中將處理進度資訊寫入管道。

  readmaxpro();為檢查狀態儲存過程,首先讀取資訊,如果資訊不存在,說明管道內沒有資訊可讀而退出;如果存在資訊則讀出資訊。

  本例子可以進行改進,輸出不通過DBMS_OUTPUT.PUT_LINE而是用返回值,那麼就可以在前端用ADO呼叫,釋出任務,任務過程中從客戶端讀取進度。程式碼如下:CREATE OR REPLACE PROCEDURE readmaxpro(p out intergr) AS


  n integer; 
  status integer; 
  begin 
  status:= DBMS_PIPE.RECEIVE_MESSAGE('maxpro',0); 
  IF status <> 0 THEN 
  P:=-1; 
  return; 
  END IF; 
  DBMS_PIPE.UNPACK_MESSAGE(p); 
  end;


  SQL> call readmaxpro();

  SQL>

  2. 執行分析

  beginmaxpro(),將主處理儲存過程放入佇列的過程,執行後儲存程式馬上返回,maxpro儲存過程放在任務佇列中,並設定為在當前系統時間執行(馬上執行)。

  maxpro為主處理儲存過程,開始執行模擬大業務處理,處理過程中將處理進度資訊寫入管道。

  readmaxpro();為檢查狀態儲存過程,首先讀取資訊,如果資訊不存在,說明管道內沒有資訊可讀而退出;如果存在資訊則讀出資訊。

  本例子可以進行改進,輸出不通過DBMS_OUTPUT.PUT_LINE而是用返回值,那麼就可以在前端用ADO呼叫,釋出任務,任務過程中從客戶端讀取進度。程式碼如下:CREATE OR REPLACE PROCEDURE readmaxpro(p out intergr) AS


  n integer; 
  status integer; 
  begin 
  status:= DBMS_PIPE.RECEIVE_MESSAGE('maxpro',0); 
  IF status <> 0 THEN 
  P:=-1; 
  return; 
  END IF; 
  DBMS_PIPE.UNPACK_MESSAGE(p); 
  end;