Oracle PL/SQL進階編程(第七彈:使用系統包:DBMS_PIPE)

DBMS_PIPE包用於在同一個Oracle的Instance,即例程的不同會話之間進行通信。管道非常類似於UNIX操作系統中的管道,但是Oracle管道並不是使用像在UNIX中那樣的操作系統調用的機制,其管道信息被緩存在系統全局區(SGA)中,當關閉Oracle例程時,就會丟失管道信息。管道又可以分爲如下兩種類型:
- 公用管道:指所有數據庫用戶都可以訪問的管道。
- 私有管道:只能由建立管道的數據庫用戶訪問。

要能訪問和執行DBMS_PIPE包中的過程,當前會話的用戶需要具有對DBMS_PIPE包的執行權限,可以以DBA用戶登錄Oracle後賦權:
GRANT EXECUTE ON DBMS_PIPE TO scott;

創建管道CREATE_PIPE

基本語法如下:

DBMS_PIPE.CREATE_PIPE(pipename    IN VARCHAR2,
                      maxpipesize IN INTEGER DEFAULT 8192,
                      private     IN BOOLEAN DEFAULT True) RETURN INTEGER;
  • pipename:用於指定管道的名稱,在調用SEND_MESSAGERECEIVE_MESSAGE時使用此參數,這個名稱在應用的數據庫實例中必須唯一。管道名不能以ORA$開頭,不能超過128個字節,不區分大小寫,不能是中文。
  • maxpipesize:用於指定管道消息的最大尺寸,以字節爲單位,不能超過8192個字節,如果超過此值會發生阻塞。
  • private:用於指定管道的類型,True表示建立私有管道,False表示建立公用管道。
    該函數返回INTEGER類型的 值,如果返回0,表示管道建立成功,否則表示失敗,會拋出ORA-23322命名衝突錯誤,表示另一個用戶創建了同名的管道。

緩存消息PACK_MESSAGE

爲了給管道發送消息,必須要先使用PACK_MESSAGE將消息寫入本地消息緩衝區,然後使用SEND_MESSAGEG將本地消息緩衝區中的消息發送到管道。PACK_MESSAGE的功能就是講消息存到私有的信息緩衝區中,該過程具有多個重載,分別接受類型爲VARCHAR2、NUMBER或DATE類型的數據項,還有兩個專門用來存儲RAW和ROWID類型的過程。基本語法如下:

DBMS_PIPE.PACK_MESSAGE(item IN VARCHAR2);
DBMS_PIPE.PACK_MESSAGE(item IN NCHAR);
DBMS_PIPE.PACK_MESSAGE(item IN NUMBER);
DBMS_PIPE.PACK_MESSAGE(item IN DATE);
DBMS_PIPE.PACK_MESSAGE_RAW(item IN RAW);
DBMS_PIPE.PACK_MESSAGE_ROWID(item IN ROWID);

在緩衝區中只能存放4096字節的數據,如果超過的限制,Oracle將拋出ORA-06558的異常。

發送消息SEND_MESSAGE

語法如下:

DBMS_PIPE.SEND_MESSAGE(pipename    IN VARCHAR2,
                       timeout     IN INTEGER DEFAULT MAXWAIT,
                       maxpipesize IN INTEGER DEFAULT 8192) RETURN INTEGER;
  • pipename:已經存在的管道的名稱,如果管道不存在,則在SEND_MESSAGE執行後,Oracle將創建該管道。
  • timeout:嘗試將信息放到管道中的時間,默認值是常量值MAXWAI,以秒爲單位,爲86400000秒,即1000天。
  • maxpipesize:管道容量的最大值,傳入管道的大小不能超過這個值。

返回值的含義:
- 返回0:表示發送成功。
- 返回1:表示超時,是由於不能獲取對管道的鎖控制,或者管道已滿,等待RECEIVE_MESSAGE從管道中清理空間超過了最長等待時間。
- 返回3:表示發送信息中斷,因爲在隱式創建管道時,如果管道內無信息,則管道會被自動刪除。

接受消息RECEIVE_MESSAGE

RECEIVE_MESSAGE用於接收管道消息,將接收到的消息寫入本地消息緩衝區,然後刪除管道中的消息,因此要特別注意,管道消息只能被接收一次。
RECEIVE_MESSAGE會在指定的管道不存在時,隱式地創建管道,並且等待接收信息。如果在指定的時間內沒有接收到消息,調用會返回同時管道自動刪除。
基本語法如下:

DBMS_PIPE.RECEIVE_MESSAGE(pipename IN VARCHAR2,
                          timeout  IN INTEGER DEFAULT MAXWAIT) RETURN INTEGER;

返回值的含義:
- 返回1:表示成功接收消息。
- 返回2:表示超時。
- 返回3:表示正在接收的消息被中斷。
如果拋出ORA-23322,表示用戶無權讀取管道。

在接收到消息後,還需要調用UNPACK_MESSAGE訪問私有數據緩衝區,以獲取信息。如果不能確認緩衝區中的數據項的類型,可以使用NEXT_ITEM_TYPE確認數據類型後,再調用UNPACK_MESSAGE獲取信息。

確定數據類型NEXT_ITEM_TYPE

基本語法如下:

DBMS_PIPE.NEXT_ITEM_TYPE RETURN INTEGER;

返回值的含義:
- 返回0:表示無數據項。
- 返回6:表示NUMBER。
- 返回9:表示VARCHAR2。
- 返回11:表示ROWID。
- 返回12:表示DATE。
- 返回23:表示RAW。

讀取緩衝區數據UNPACK_MESSAGE

語法如下:

DBMS_PIPE.UNPACK_MESSAGE(item OUT VARCHAR2);
DBMS_PIPE.UNPACK_MESSAGE(item OUT NCHAR);
DBMS_PIPE.UNPACK_MESSAGE(item OUT NUMBER);
DBMS_PIPE.UNPACK_MESSAGE(item OUT DATE);
DBMS_PIPE.UNPACK_MESSAGE_RAW(item OUT RAW);
DBMS_PIPE.UNPACK_MESSAGE_ROWID(item OUT ROWID);

如果緩衝區中沒有數據或類型不匹配,則會觸發ORA-06556ORA-06559,因此最好在接收之前,使用NEXT_ITEM_TYPE確定緩衝區中下一個項目的數據類型。

UNPACK_MESSAGE每次只能取出一條消息,如果要取出多條消息,需要多次調用UNPACK_MESSAGE

刪除管道REMOVE_PIPE

刪除管道後,管道中還未被提取的信息在管道被刪除前統一會被刪除,語法如下:
DBMS_PIPE.REMOVE_PIPE(pipename IN VARCHAR2) RETURN INTEGER;
返回0表示管道被成功刪除,如果用戶沒有刪除這個管道的權限,則會拋出ORA-23322

清除管道內容PURGE

用於清除命名管道中的所有信息,對於隱式創建的管道,會根據最近最少使用的算法將此管道從全局共享內存區中清除,實際上就是釋放了管道所佔用的內存。PURGE會自動調用RECEIVE_MESSAGEG,將私有數據緩衝區重寫覆蓋,語法如下:
DBMS_PIPE.PURGE(pipename IN VARCHAR2)

復位管道緩衝區RESET_BUFFER

該過程將重置PACK_MESSAGEUNPACK_MESSAGE指針的位置,使之指到私有數據緩衝區的頭部,語法如下:
DBMS_PIPE.RESET_BUFFER;

返回會話名稱UNIQUE_SESSION_NAME

該函數用來爲特定會話返回唯一的名稱,名稱的最大長度爲30個字節,對於同一會話來說,其值不會改變,語法如下:
DBMS_PIPE.UNIQUE_SESSION_NAME RETURN VARCHAR2;

使用管道的例子

由於管道用於在多個會話之間傳遞數據,因此需要一個會話發送消息,另一個會話接收消息,基本實現過程如下:
1. 一個會話發哦少年宮消息到管道時,需要首先將消息寫入本地消息緩衝區中,然後將本地消息緩衝區內容發送到管道。
2. 當接收管道消息時,需要首先使用本地消息緩衝區接收管道消息,然後從消息緩衝區取得具體消息。

代碼如下:

--發送管道消息
CREATE OR REPLACE PROCEDURE send_pipe_message(pipename VARCHAR2,message VARCHAR2)
IS
   flag INT;
BEGIN
   flag:=DBMS_PIPE.create_pipe(pipename);           --創建管道
   if flag=0 THEN                                   --如果管道創建成功
      DBMS_PIPE.pack_message(message);              --將消息寫到本地緩衝區
      flag:=DBMS_PIPE.send_message(pipename);       --將本地緩衝區中的消息發送到管道
   END IF;
END;

--從管道中接收消息
CREATE OR REPLACE PROCEDURE receive_pipe_message(pipename VARCHAR2,message VARCHAR2)
IS
   flag INT;
BEGIN
   falg:=DBMS_PIPE.receive_message(pipename);  --從管道中獲取消息,保存到緩衝區
   IF flag=0 THEN
      DBMS_PIPE.unpack_message(message);       --從緩衝區讀取消息
      flag:=DBMS_PIPE.remove_pipe(pipename);   --移除管道
   END IF;
END;

可以使用usera登錄,調用send_pipe_message向管道發送一條消息,然後用userb登錄,調用receive_pipe_message獲取消息。

發佈了165 篇原創文章 · 獲贊 47 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章