客戶端呼叫大型預存程序(跑批、報表、ETL),**同步阻塞**導致:
Client → BEGINMAXPRO() → DBMS_JOB.SUBMIT → Job Queue → MAXPRO() (Background)
↓
DBMS_PIPE.PACK/SEND → Pipe 'maxpro'
↓
Client → READMAXPRO() → DBMS_PIPE.RECEIVE/UNPACK → 進度顯示
JOB_QUEUE_PROCESSES = 10(動態可修改)。JOB_QUEUE_INTERVAL = 1(秒)。GRANT EXECUTE ON DBMS_PIPE TO app_user;
GRANT EXECUTE ON DBMS_LOCK TO app_user;
GRANT EXECUTE ON DBMS_JOB TO app_user;
MAXPRO(模擬 30 秒長任務)
CREATE OR REPLACE PROCEDURE maxpro AS
n INTEGER;
status NUMBER;
BEGIN
DBMS_PIPE.PURGE('maxpro'); -- 清舊訊息
FOR n IN 1..30 LOOP
DBMS_PIPE.PACK_MESSAGE(n);
status := DBMS_PIPE.SEND_MESSAGE('maxpro');
DBMS_LOCK.SLEEP(1); -- 模擬工作 1 秒
END LOOP;
DBMS_PIPE.PURGE('maxpro');
DBMS_PIPE.PACK_MESSAGE(999999); -- 完成標記
status := DBMS_PIPE.SEND_MESSAGE('maxpro');
END maxpro;
/
READMAXPRO(非阻塞讀取)
CREATE OR REPLACE PROCEDURE readmaxpro(p_progress OUT INTEGER) AS
n INTEGER;
status INTEGER;
BEGIN
-- timeout=0 非阻塞:無訊息立即返回 status=1
status := DBMS_PIPE.RECEIVE_MESSAGE('maxpro', 0);
IF status != 0 THEN
p_progress := -1; -- 管道無資料
RETURN;
END IF;
DBMS_PIPE.UNPACK_MESSAGE(p_progress);
END readmaxpro;
/
關鍵:**RECEIVE_MESSAGE(pipe, 0) 秒數為 0**,表示不等待,立即返回狀態碼:
BEGINMAXPRO(提交 Job 立即返回)
CREATE OR REPLACE PROCEDURE beginmaxpro AS
v_job BINARY_INTEGER;
BEGIN
DBMS_JOB.SUBMIT(v_job, 'maxpro;', SYSDATE, NULL, FALSE);
DBMS_OUTPUT.PUT_LINE('Job Queue No: ' || v_job);
COMMIT; -- Job 提交必須 COMMIT 才生效
END beginmaxpro;
/
SQL> SET SERVEROUTPUT ON
SQL> CALL beginmaxpro();
Job Queue No: 21
Call completed.
SQL> CALL readmaxpro();
maxpro 目前進度: 14
Call completed.
SQL> CALL readmaxpro();
maxpro 目前進度: 16
Call completed.
SQL> CALL readmaxpro();
maxpro 目前進度: 23
Call completed.
SQL> CALL readmaxpro();
maxpro 目前進度: 999999 -- 完成
Call completed.
SQL> CALL readmaxpro();
管道中目前無訊息回傳
Call completed.
OUT 參數回傳進度(如上 p_progress OUT INTEGER),ADO/ODBC/JDBC 可直接取得回傳值。DBMS_JOB.REMOVE(job_no) 或在 MAXPRO 內檢查控制表/管道指令實現優雅停止。SEND_MESSAGE 指令至另一管道,主程序 RECEIVE_MESSAGE 檢查是否收到停止/暫停指令。DBMS_JOB,支援鏈式任務、事件驅動、資源管理、日曆語法。DBMS_PIPE,發布/訂閱模型,支援多消費者、信號通知。DBMS_JOB + DBMS_PIPE 是 Oracle 9i/10g 時代實現長任務非同步監控的經典組合。核心在於**「Job 脫離 Session 執行」+「Pipe 非阻塞狀態傳遞」**。理解 RECEIVE_MESSAGE(timeout=0) 非阻塞語意與 COMMIT 觸發 Job 執行的時機,即可構建穩定的背景作業監控體系。