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秒,表示,呼叫時如果沒有資訊不等待直接返回。
--接受等待時間為1秒,可以為0,立即呼叫或DBMS_PIPE.
5.-起動模擬大業務處理儲存過程為後臺程序的儲存過程(BEGINMAXPRO)。通過DBMS_JOB.SUBMIT(JOB,'maxpro;',sysdate,NULL,FALSE);使"maxpro"為一個任務,在當前時間(sysdate)後執行,當然如果把sysdate改一具體時間,那就在具體時間執行
|
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> 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; |