為什麼 PL/SQL 需要多進程通訊
PL/SQL 設計初衷是強化 SQL 處理能力,缺乏原生多執行緒/多進程支援。若需並行處理提升吞吐量,必須透過 Oracle 提供的兩個套件實現會話間通訊:
- DBMS_PIPE:命名管道,點對點、非同步、訊息佇列模型
- DBMS_ALERT:事件通知/發布-訂閱模型,同步於交易提交
DBMS_PIPE 核心 API
| 函數/程序 | 用途 |
| PACK_MESSAGE(msg) | 將訊息封裝進本地緩衝區 |
| SEND_MESSAGE(pipe_name, timeout) | 發送緩衝區至命名管道,回傳狀態碼 (0=成功) |
| RECEIVE_MESSAGE(pipe_name, timeout) | 從管道接收訊息至本地緩衝區 |
| UNPACK_MESSAGE(var) | 解析緩衝區訊息至變數 |
| CREATE_PIPE / REMOVE_PIPE | 建立/移除管道 (隱含於首次 SEND) |
| PURGE / RESET_BUFFER | 清除管道/本地緩衝區 |
DBMS_PIPE 範例:雙會話請求-回應
發送端 (Session A)
DECLARE
v_pipe VARCHAR2(30) := 'pipe_req';
v_status INTEGER;
BEGIN
DBMS_PIPE.PACK_MESSAGE('HELLO FROM SENDER');
v_status := DBMS_PIPE.SEND_MESSAGE(v_pipe, 10);
IF v_status != 0 THEN
DBMS_OUTPUT.PUT_LINE('Send failed: ' || v_status);
END IF;
END;
/
接收端 (Session B)
DECLARE
v_pipe VARCHAR2(30) := 'pipe_req';
v_status INTEGER;
v_msg VARCHAR2(200);
BEGIN
v_status := DBMS_PIPE.RECEIVE_MESSAGE(v_pipe, 30);
IF v_status != 0 THEN
DBMS_OUTPUT.PUT_LINE('Receive failed: ' || v_status);
ELSE
DBMS_PIPE.UNPACK_MESSAGE(v_msg);
DBMS_OUTPUT.PUT_LINE('Got: ' || v_msg);
END IF;
END;
/
DBMS_ALERT 核心 API
| 程序 | 用途 |
| REGISTER(alert_name) | 註冊監聽指定警示名稱 |
| SIGNAL(alert_name, message) | 發送警示訊息 (於 COMMIT 時真正發送) |
| WAITONE(alert_name, msg OUT, status OUT, timeout) | 等待單一警示,逾時返回 |
| WAITANY(alerts, name OUT, msg OUT, status OUT, timeout) | 等待任一已註冊警示 |
| REMOVE/REMOVEALL | 移除註冊 |
DBMS_ALERT 範例:異步事件通知
發送端
DECLARE
v_alert VARCHAR2(30) := 'order_event';
BEGIN
DBMS_ALERT.SIGNAL(v_alert, 'New order #12345 inserted');
COMMIT; -- 必須 COMMIT 才會真正發送
END;
/
接收端
DECLARE
v_alert VARCHAR2(30) := 'order_event';
v_msg VARCHAR2(200);
v_status INTEGER;
BEGIN
DBMS_ALERT.REGISTER(v_alert);
DBMS_ALERT.WAITONE(v_alert, v_msg, v_status, 60); -- 等待 60 秒
IF v_status = 0 THEN
DBMS_OUTPUT.PUT_LINE('Alert received: ' || v_msg);
ELSE
DBMS_OUTPUT.PUT_LINE('Timeout or error: ' || v_status);
END IF;
END;
/
兩者關鍵差異比較
| 特性 | DBMS_PIPE | DBMS_ALERT |
| 通訊模型 | 點對點管道 (佇列) | 發布-訂閱 (廣播) |
| 同步性 | 非同步,立即發送/接收 | 同步於 COMMIT,ROLLBACK 則不發送 |
| 訊息消費 | 單一接收者消費後移除 | 多訂閱者皆可收到 (僅複製) |
| 資料型別 | 支援 VARCHAR2, NUMBER, DATE, RAW 等 (透過 PACK/UNPACK) | 僅 VARCHAR2 文字訊息 |
| 緩衝區大小 | 受限於 SGA pipe_size (預設 8K) | 較小,適合簡短通知 |
| 典型用途 | 背景作業協調、外部程式互動、複雜資料傳遞 | 事件驅動觸發、快取失效通知、跨會話訊號 |
進階應用模式
- 工作隊列:主進程將任務封裝送入管道,多個 Worker 進程並行 RECEIVE/PROCESS/回覆結果管道。
- 快取失效廣播:資料變更時 SIGNAL 'cache_inval_
',應用層會話 REGISTER/WAITONE 即時刷新本地快取。
- 外部程式整合:Pro*C/Oracle Call Interface (OCI) 進程作為管道端點,實現資料庫與 OS 層雙向通訊 (如前文 DBMS_PIPE 範例)。
效能與限制提醒
- 管道訊息駐留於 SGA,大量/大訊息可能衝擊共用池,需監控
V$DB_PIPES。
- ALERT 訊號在 COMMIT 前不會發送,長交易會延遲通知;若需即時性請用 PIPE。
- 兩者皆非持久化,資料庫重啟後管道/警示消失,重要狀態須自行持久化至表格。
- 12c+ 可考慮
DBMS_AQ (Advanced Queuing) 取代,提供持久化、優先級、延遲投遞等企業級佇列功能。
- 上一篇文章: Oracle 回滾段損壞重建完整操作手冊
- 下一篇文章: Oracle 互聯網檔案系統 (iFS) 實踐:OracleFilesOnline 全球 4.5 萬用戶部署案例
Copyright ©
程式碼之家 All Rights Reserved