使用oracle pipe傳遞消息
2024-08-29 13:38:03
供稿:網友
 
             
  1.管道操作
  1.1管道的通訊機制: 
  消息發送者把消息發送到本地消息緩沖區,本地消息緩沖區的消息發送到數據庫指定實例的UGA區域,消息接收者從數據庫管道獲取消息并且放到本地消息緩沖區,然后從本地消息緩沖區讀取消息。
                                                                                              由于數據庫把管道建立在數據庫實例的UGA區域,所以管道式可以實現同一個數據庫實例下不同數據庫會話之間的通訊的。
  注重:管道消息是獨立于事務的,也就是說不能回滾得,并且同一個管道消息只能被一個用戶接收。也就是說要實現消息的廣播,還需要在管道上的通訊機制上,自己做進一步的工作。
  1種方式就是采用循環的方式,對需要接收消息的用戶按照數據庫會話的方式,一個循環下來對每一個數據庫會話都發送一條消息(按照會話內通訊(消息的尋址)的方式進行處理)。
  用戶可以定義自己的協議來實現管道消息。參考下面的例子。
  內容較多的消息的發送和接收。對于那些需要發送大的消息,應該考慮采用數據表的方式,通過管道可以發送消息的簡要信息,真正的消息內容保存到一個數據表中去,
  當用戶通過管道獲得消息后,解析消息,然后去相應的數據表獲取真正的消息內容。
  1.2發送消息/接收消息
  ---發送消息到指定管道
  declare 
  i integer;
  j integer;
  begin
  for j in 1..10loop
  dbms_pipe.pack_message('wdz'j);
  end loop;
  dbms_pipe.pack_message('end');
  i := dbms_pipe.send_message('apple');
  if i =0 then
  dbms_output.put_line('ok--發送消息成功!');
  
  end if;
  end;
  
  ---從指定管道接受消息
  declare 
  i integer;
  ch varchar2(200);
  flag boolean :=false;
  begin
  i := dbms_pipe.receive_message('apple',100);
  if(i=0)then
  dbms_output.put_line('ok---預備接受消息');
  else
  flag := true; 
  end if;
  while(not flag) loop
  dbms_pipe.unpack_message(ch); 
  if(upper(ch)='END') then
  flag := true;
  dbms_output.put_line('接收消息完成'); 
  else
  dbms_output.put_line('消息內容='ch); 
  end if;
  end loop;
  end;
  
  1.3使用自己定義的協議發送/接收消息
  -- Created on 2003-11-10 by wdz
  ---發送消息到指定管道
  ---自己定義的消息協議
  ---用消息對的方式發送和接收消息。
  ---消息對的第一個消息作為消息頭表明消息對的第2個消息的類型。
  ---消息對的第2個消息表明消息對的消息體
  --- c 表示消息體為字符型
  --- d 表示消息體為日期型
  --- n 表示消息體為數字型
  declare 
  i integer;
  j integer;
  begin
  
  dbms_pipe.pack_message('c');
  dbms_pipe.pack_message('消息體為字符型');
  dbms_pipe.pack_message('d');
  dbms_pipe.pack_message(sysdate);
  dbms_pipe.pack_message('n');
  dbms_pipe.pack_message(1000);
  
  dbms_pipe.pack_message('end');
  i := dbms_pipe.send_message('apple');
  if i =0 then
  dbms_output.put_line('ok--發送消息成功!');
  
  end if;
  end;
  
  
  ---從指定管道接受消息
  ---自己定義的消息協議
  ---用消息對的方式發送和接收消息。
  ---消息對的第一個消息作為消息頭表明消息對的第2個消息的類型。
  ---消息對的第2個消息表明消息對的消息體
  --- c 表示消息體為字符型
  --- d 表示消息體為日期型
  --- n 表示消息體為數字型
  declare 
  i integer;
  ch varchar2(200);
  ch2 varchar2(200); 
  msgDate date;
  msgNum number;
  msgString varchar2(1000); 
  flag boolean :=false;
  begin
  i := dbms_pipe.receive_message('apple',100);
  if(i=0)then
  dbms_output.put_line('ok---預備接受消息');
  else
  flag := true; 
  end if;
  while(not flag) loop
  dbms_pipe.unpack_message(ch); 
  if(upper(ch)='END') then
  flag := true;
  dbms_output.put_line('接收消息完成'); 
  else 
  if ch='d' then
  dbms_pipe.unpack_message(msgDate); 
  dbms_output.put_line('日期消息內容='to_char(msgDate,'yyyy-mm-dd hh24:mi:ss'));
  elsif ch='n' then
  dbms_pipe.unpack_message(msgNum); 
  dbms_output.put_line('數字型消息內容='to_char(msgNum)); 
  elsif ch='c' then
  dbms_pipe.unpack_message(msgString); 
  dbms_output.put_line('字符型消息內容='msgString);
  end if ; 
  end if;
  end loop;
  end;
  
  1.4會話內通訊(消息的尋址)
  -- Created on 2003-11-10 by wdz
  ---從在當前數據庫會話內使用管道發送消息
  declare 
  i integer;
  j integer;
  begin
  dbms_pipe.pack_message('測試發送字符串消息');
  dbms_pipe.pack_message(sysdate);
  dbms_pipe.pack_message(2000);
  dbms_pipe.pack_message('最后一條消息');
  ---- 使用 dbms_pipe.unique_session_name來指定管道名稱,這樣可以按照數據庫會話來實--現會話內通訊,當然也可以自己來定義1種會話的命名方式,只要能夠名稱按照會話名字唯一--就可以了。
                         
  i := dbms_pipe.send_message(dbms_pipe.unique_session_name);
  if i =0 then
  dbms_output.put_line('ok--發送消息成功!'); 
  end if;
  end;
  
  ---- -- Created on 2003-11-10 by wdz
  ---從在當前數據庫會話內使用管道接受消息
  ---- 使用 dbms_pipe.unique_session_name來指定管道名稱,這樣可以按照數據庫會話來
  --實--現會話內通訊,當然也可以自己來定義1種會話的命名方式,只要能夠名稱按照會話名字唯一--就可以了。
  
  declare
  i integer;
  ch varchar2(1000);
  msgDate date;
  msgNum number;
  msgString varchar2(1000);
  flag boolean := false;
  begin
  i := dbms_pipe.receive_message(dbms_pipe.unique_session_name, 100);
  if (i = 0) then
  dbms_output.put_line('ok---預備接受消息');
  else
  flag := true;
  end if;
  while (not flag) loop
  i := dbms_pipe.next_item_type;
  if (i = 0) then
  flag := true;
  dbms_output.put_line('##接收消息完成');
  elsif i = 12 then-- 12 date
  dbms_pipe.unpack_message(msgDate);
  dbms_output.put_line('日期消息內容=' to_char(msgDate, 'yyyy-mm-dd hh24:mi:ss'));
  elsif i =6 then --6 number
  dbms_pipe.unpack_message(msgNum);
  dbms_output.put_line('數字型消息內容='  to_char(msgNum));
  elsif i = 9 then -- 9 varchar2 
  dbms_pipe.unpack_message(msgString);
  dbms_output.put_line('字符型消息內容='  msgString);
  end if;
  end loop;
  end;
  
  1.5.執行權限
  擁有DBA權限的用戶可以在pl/sql 塊訪問dbms_pipe,但是不能在存儲過程執行。因為該包禁止角色執行。應該是通過dba把dbms_pipe的execute權限分配給指定用戶。
  也就是一個用戶即使是dba也需要獲得dbms_pipe的execute權限,才能在存儲過程中使用。