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权限,才能在存储过程中使用。